home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 August: Technology Seed / ADC Seed CD - August 1999.toast / Carbon SDK 1.0d10c3 / Sample Code / SimpleText / SimpleText.c < prev    next >
Encoding:
Text File  |  1999-05-04  |  143.9 KB  |  5,319 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        SimpleText.c
  3.  
  4.     Contains:    SimpleText - a simple document editing application for shipping
  5.                              with system software.
  6.  
  7.     Version:    SimpleText 1.4 or later
  8.  
  9.     Written by:    TED = Tom Dowdy
  10.                 DAL = Dave Lyons
  11.  
  12.     Copyright:    © 1993-1998 by Apple Computer, Inc., all rights reserved.
  13.  
  14.     File Ownership:
  15.  
  16.         DRI:                Tom Dowdy
  17.  
  18.         Other Contact:        Jim Negrette
  19.  
  20.         Technology:            Macintosh Graphics Group
  21.  
  22.     Writers:
  23.  
  24.         (dmp)    Dave Polaschek
  25.         (ecs)    Eric Schlegel
  26.         (ted)    Tom Dowdy
  27.         (Gr)    Greg Robbins
  28.         (TD)    Tom Dowdy
  29.  
  30.     Change History (most recent first):
  31.  
  32.     $Log: SimpleText.c,v $
  33.     Revision 1.37  1999/04/15 23:27:36  ericsc
  34.     Fix starting item index in AreAllMenuItemsEnabled; remove EnsureAppleMenu.
  35.  
  36.     Revision 1.36  1999/04/12 19:04:36  poon
  37.     Carbonized printing loop
  38.     
  39.     Revision 1.35  1999/04/08 21:47:02  voas
  40.     Change to always call InitCursor. This seems to cause the drag manager
  41.     to get initialized. No, I'm not kidding.
  42.     
  43.     Revision 1.34  1999/04/01 22:53:26  devans
  44.     Add code to Compile and Execute selections as AppleScripts.
  45.     
  46.     Revision 1.33  1999/03/03 23:14:29  guyf
  47.     Use new control creation APIs instead of NewControl
  48.     
  49.     Revision 1.32  1999/02/19 22:10:59  danp
  50.     Changes to support opaque regions.
  51.     
  52.     Revision 1.31  1999/02/16 01:02:33  christ
  53.     Use GetQDGlobalsScreenBits, not qd.screenBits, when calling DragWindow
  54.     
  55.     Revision 1.30  1999/02/16 00:41:39  christ
  56.     Integrate document proxy icon support
  57.     
  58.     Revision 1.29  1999/02/10 01:01:01  danp
  59.     Adding Andy Carroll's changes so we compile correctly on both X and MacOS 8.5
  60.     
  61.     Revision 1.28  1999/02/05 18:58:25  ericsc
  62.     Use Enable/DisableAllMenuItems.
  63.     
  64.     Revision 1.27  1999/01/26 23:40:19  wilkes
  65.     Update for opaque AEDesc's.
  66.     
  67.     Revision 1.26  1999/01/08 04:42:00  christ
  68.     Text dragging support is back.
  69.  
  70.     Revision 1.25  1998/12/03 00:05:48  kilroy
  71.     Removed Balloons and AppleGuide
  72.     
  73.     Revision 1.24  1998/11/25 21:01:20  wilkes
  74.     Removed all GX references.
  75.     
  76.     Revision 1.23  1998/11/19 01:16:19  wilkes
  77.     Removed reliance on QuickTime.  Most changes were conditionalized with
  78.     ALLOW_QUICKTIME...
  79.  
  80.     Revision 1.22  1998/11/11 22:28:56  wilkes
  81.     Fixed various problems caused by the interface changes made by Nitin earlier,
  82.     mostly involving static RoutineDescriptors...
  83.  
  84.     Revision 1.21  1998/10/19 23:53:46  voas
  85.     Make work with latest HLTB.
  86.  
  87.     Revision 1.20  1998/10/14 18:52:47  voas
  88.     Eliminate all warnings. Get working with top of tree.
  89.     
  90.     Revision 1.19  1998/10/12 18:59:00  danp
  91.     Modifications to allow cross-compiling and for CarbonLib support. Removed lots of GX stuff
  92.     
  93.     Revision 1.18  1998/10/01 23:00:37  marke
  94.     in DoGrowWindow, add call to GetWindowPortBounds to update pData->contentRect. Nothing works unless content rect is updated after a resize, so this must've been an introduced bug
  95.     
  96.     Revision 1.17  1998/09/29 23:22:24  kilroy
  97.     Fixed some stuff that I thought we already fixed. Like using InvalWindowRect.
  98.     
  99.     Revision 1.16  1998/09/15 22:54:15  voas
  100.     Changed to reflect latest Carbon header changes I just made.
  101.     
  102.     Revision 1.15  1998/09/15 18:59:48  jiarocci
  103.     SimpleText now builds with -DTARGET_CARBON=1. Still needs further cleanup.
  104.     
  105.     Revision 1.14  1998/09/15 00:19:25  mkellner
  106.     Make Navigation support
  107.  
  108.     Revision 1.13  1998/09/12 23:09:09  voas
  109.     Convince it to work without passing in storage for windows.
  110.     
  111.     Revision 1.12  1998/09/02 20:44:07  danp
  112.     Minor changes for blue mwerks compiles
  113.  
  114.     
  115.     Revision 1.11  1998/08/31 05:12:32  danp
  116.     Removed AEGetAttributeDesc workaround.
  117.  
  118.     Revision 1.10  1998/08/27 23:21:07  danp
  119.     Added new #includes for SimpleText.r because of new interfaces layout
  120.     Placed stub for AEGetAttributeDesc due to undefined symbol in Carbon.
  121.     Will need to remove once devans fixes that symbol.
  122.     
  123.     Revision 1.9  1998/08/24 20:58:56  voas
  124.     Fix bug getting structure bounds. We were hanging onto a pointer to rgn bounds inside a deleted region.
  125.     
  126.     Revision 1.8  1998/05/10 07:28:35  devans
  127.     Hack for TextEdit font size bug.  Set and change the font size when
  128.     we first fill in a TextEdit handle.  This causes the right calcs to
  129.     occur.  Also return NULL from OpenDoc instead of whatever was on the
  130.     stack.
  131.     
  132.     Revision 1.7  1998/05/06 22:21:25  devans
  133.     Replace usage of qd.arrow with GetQDarrow().
  134.     
  135.     Revision 1.6  1998/04/21 02:13:22  mkellner
  136.     Add SimpleText app wrapper
  137.     
  138.     Revision 1.5  1998/03/30 22:12:29  mkellner
  139.     Update to use new GetQDxxxx macros for qd.globals
  140.     
  141.     Revision 1.4  1998/03/21 04:13:15  mkellner
  142.     Add a define for qd_screenBits for qd.screenBits.
  143.     Replaced qd.screenBits with qd_screenBits
  144.     
  145.     Revision 1.3  1998/03/20 03:20:03  mkellner
  146.     change qd.thePort to FrontWindow()
  147.     add SysEnvirons
  148.     
  149.     Revision 1.2  1998/03/19 03:55:40  mkellner
  150.     - Add <ConditionalMacros.h> and <QTMLMapNames.h>
  151.     - Fix captialization of math.h, stdio.h, strings.h, etc.
  152.     - Change Types.h, Memory.h and Windows.h to MacTypes, MacMemory, and MacWindows
  153.     - Add inital set of stubs.
  154.     - Change Types.r to MacTypes.r
  155.     
  156.     Revision 1.1.1.1  1998/03/18 22:56:11  ivory
  157.     Initial checkin of SimpleText.
  158.     
  159.         
  160.         16    2/23/98 3:22 PM Tom Dowdy
  161.         Test for negative width rectangles to avoid sometimes creating a new
  162.         staggered window that wasn't actually there.
  163.         
  164.         15    9/30/97 6:29 PM Sam Bushell
  165.         Now tests unrecognised file types to see if there are graphics
  166.         importers for them, and uses PICTFile if there are.
  167.         
  168.         14    9/26/97 2:34 PM Tom Dowdy
  169.         Fixed extended picture size rectangle
  170.         
  171.         13    9/2/97 9:02 AM Tom Dowdy
  172.         NIL finds are now just treated as cancels.
  173.         
  174.         12    8/20/97 4:24 PM Tom Dowdy
  175.         1674136: adjust cursor after select all
  176.         
  177.         11    8/18/97 12:18 PM Duane Byram
  178.         don't need to increment kControlScrollBarLiveProc because of
  179.         Appearance.h change
  180.         
  181.         10    8/12/97 4:04 PM Tom Dowdy
  182.         new staggering
  183.         
  184.         9     8/11/97 3:36 PM Tom Dowdy
  185.         Nav services now working!
  186.         
  187.         8     8/11/97 3:01 PM Tom Dowdy
  188.         rolling in nav services
  189.         
  190.         7     7/30/97 4:05 PM Tom Dowdy
  191.         Adjust cursor before mouse down
  192.         
  193.         6     7/30/97 3:42 PM Tom Dowdy
  194.         Live scrolling now
  195.         
  196.         5     7/29/97 6:27 PM Tom Dowdy
  197.         Added appearance
  198.         
  199.         4     7/29/97 6:02 PM Tom Dowdy
  200.         'rapp' event support
  201.         
  202.         3     7/29/97 2:06 PM Tom Dowdy
  203.         Removed all of the old and boring refs
  204.         
  205.         2     7/29/97 1:52 PM Tom Dowdy
  206.         Various new interface fixes
  207.         
  208.         1     7/28/97 11:20 AM Duane Byram
  209.         first added to Source Safe project
  210.  
  211.         <49>     6/30/97    ted        [1657956]  Incorrect drag bounds
  212.         <48>     5/14/97    ted        More drag clipping bug fixes
  213.         <47>     4/28/97    ted        [1650434]  Crash w/ QuickTime -- also fix incompat w/ AppleGuide
  214.         <46>     1/13/97    ted        fixing jump table offset link problems
  215.         <45>      1/2/97    ecs        call preMenuAccessProc before tracking menus
  216.         <44>      1/2/97    ecs        invalidate cursor region when windows are opened & closed;
  217.                                     unhilite menu before adjust menus in DoCloseWindow to avoid ugly
  218.                                     menu hilite flashing; InitCursor before menu tracking to make
  219.                                     sure we've got an arrow cursor
  220.         <43>    12/20/96    ted        [1614876]  'rapp' event
  221.         <42>    12/19/96    ted        [1395082]  Remove profiler
  222.         <41>     12/6/96    ecs        boot speed improvements: custom GetNewMBar, delayed Apple menu
  223.                                     construction, don't redraw menu bar if AdjustMenus already did,
  224.                                     cache menu handles in AdjustMenus
  225.         <40>     12/5/96    ted        Removing quit after print. Don't need to do that.
  226.         <39>     12/5/96    ted        [1609760]  Adding drag flavor for clipping title
  227.         <38>     12/3/96    ted        [1608948]  Fixing find for half script stuff.
  228.         <37>     12/3/96    ted        [1608989]  Unhilite menu before find dialog
  229.         <36>    11/26/96    ecs        support GXGraphics extension; smarter cursor adjustment; delay
  230.                                     menu unhiliting to provide more feedback
  231.         <35>      9/9/96    dmp        Fix my Homer with when to include qd
  232.         <34>      9/9/96    dmp        staticfy functions that are local to eliminate warnings in
  233.                                     MWERKS compilers. Also fix the #ifdef on the qd globals.
  234.         <33>     8/28/96    ted        fixing errors on printing with abort
  235.         <32>     8/21/96    ecs        sometimes don't need QDGlobals
  236.         <31>     7/24/96    ted        fixing stupid ttro draw hook bug
  237.         <30>     7/18/96    ted        fixing menu nil dereference
  238.         <29>      7/9/96    ted        1366267: menu bar flashing
  239.         <28>     6/10/96    ted        error dialog shouldn't use 7.x features on 6.x system
  240.         <27>      6/5/96    ted        removing hack code no longer needed for spell catcher
  241.         <26>      6/4/96    ted        for PPC, check symbols in addition to Gestalt
  242.         <25>     5/31/96    ted        adding UPPs for all printing message stuff
  243.         <24>     5/31/96    ted        adding PPC, FAT, and NuKernel builds
  244.         <23>     5/29/96    ted        don't assume window across WNE (sheash!)
  245.         <22>     5/29/96    ted        always finish event when front window isn't one we know about
  246.         <21>     5/10/96    ted        fixing possible infinite loop in quitting w/ non closable
  247.                                     windows
  248.         <20>     4/30/96    ted        moving segments to initialize
  249.         <19>     4/17/96    ted        adding support for external guide files
  250.         <18>     4/11/96    ted        cwindowptr->windowptr
  251.         <17>     4/10/96    ted        don't close desk acc windows
  252.         <16>      3/7/96    ted        fixing print attempt for dragging things to DTPs
  253.         <15>     2/15/96    ted        adding qd for new libraries
  254.         <14>      2/8/96    ted        CountMenuItems->CountMItems (??)
  255.         <13>      1/4/96    ecs        resegment for threads
  256.         <12>      1/4/96    ecs        font menu & AG threads
  257.         <11>     12/6/95    ted        adding file type to prefligth
  258.         <10>    11/13/95    ted        don't close docs already open after print
  259.          <9>    11/10/95    ted        converting error dialog to moveable modal
  260.          <8>     11/9/95    ted        adding content region check for adjust cursor
  261.          <7>     11/2/95    ted        BlockMoveData
  262.          <6>    10/31/95    ted        testing some resolutions
  263.          <5>    10/31/95    ted        adding support for high-res pict scaling
  264.          <4>     10/2/95    TD        adding support for SC compiler
  265.          <3>     9/15/95    Gr        For contents menu support, make AdjustMenus and EnableCommand
  266.                                     defensive against nil menu handles
  267.          <2>     8/22/95    TD        moving enum to simpletext.h
  268.          <1>     8/21/95    TD        First checked in.
  269.         <61>      1/31/95    TED        GX printing was removing too much from pages (#1214713)
  270.         <60>      1/4/95    DAL        Move the SetWTitle for "untitled" here from TextFile.c (to fix
  271.                                     an Apple Menu Options problem, Radar #s 1207631 and 1207614).
  272.         <59>    1/3/95        TED        Radar #1166592.  Don't touch justification in the right to left case.
  273.         <58>    12/21/94    DAL        Radar #1207643. Made AdjustScrollBars only show the controls if
  274.                                     the owning window is hilited (for dragging text from another
  275.                                     window).
  276.         <57>     12/8/94    DAL        Radar #1204706. Now handles updates behind GetFile dialogs
  277.                                     (CustomGetFile, or CustomGetFilePreview if QuickTime is
  278.                                     available). Also, the save-changes filter was handling
  279.                                     keystrokes but wasn't updating windows.
  280.         <50>     10/4/94    TED        Window to front if doc already open (#116448).
  281.         <49>      9/8/94    DAL        AdjustMenus when last window is closed (#1148445). Added key
  282.                                     shortcuts for the Don't Save button (#110047). Untitled window
  283.                                     number increments only when appropriate (#1183083), resets when
  284.                                     there are no windows open, and the first untitled window has no
  285.                                     number (#1148458). We now handle updates behind the save-changes
  286.                                     alert.
  287.  
  288. */
  289. #define TARGET_CARBON 1
  290. #define ACCESSOR_CALLS_ARE_FUNCTIONS 1
  291. #include "MacIncludes.h"
  292.  
  293. #include <Appearance.h>
  294. #include <Controls.h>
  295. #include <ControlDefinitions.h>
  296. #include <ImageCompression.h>    // for CustomGetFilePreview
  297. #include <Threads.h>
  298. #include <Components.h>        // for AppleScript
  299. #include <OSA.h>        // for AppleScript
  300. // #include "GraphicsImporter.h"
  301. #if ALLOW_QUICKTIME
  302. #include "QuickTimeComponents.h"
  303. #endif
  304.  
  305. #define CompilingMain 1
  306.  
  307. #include "SimpleText.h"
  308. #include "Clipboard.h"
  309.  
  310. #include <PMApplication.h>
  311.  
  312. #define qSingleSelectionOnly 1        // MDK - for CARBON since we don't do AppleEvents through HighLevel events yet.
  313.  
  314. // amount of time we leave a menu title hilited after a cmd key is used
  315. #define kMenuHiliteDelay 2
  316.  
  317.  
  318. #define ff(x)        ((Fixed)(x) << 16)
  319.  
  320.  
  321. // --------------------------------------------------------------------------------------------------------------
  322. // FORWARD DECLARES
  323. // --------------------------------------------------------------------------------------------------------------
  324. void    UnhiliteMenuDelayed(unsigned long keyTime);
  325. OSErr     DoActivate(WindowPtr pWindow, Boolean activating);
  326. OSErr    DoCommand(WindowPtr pWindow, short commandID, long menuResult, long keyTime);
  327. OSErr    DoKeyEvent(WindowPtr pWindow, EventRecord * pEvent, Boolean processPageControls);
  328. Boolean CommandToIDs(short commandID, short * menuID, short *itemID);
  329. Boolean    AdjustMenus(WindowPtr pWindow, Boolean editDialogs, Boolean forceTitlesOn);
  330.  
  331. static Boolean CloseAllWindows( Boolean quitting );
  332.  
  333. static void SynchronizeFiles( void );
  334.  
  335.  
  336. // --------------------------------------------------------------------------------------------------------------
  337. // GLOBAL VARIABLES
  338. // --------------------------------------------------------------------------------------------------------------
  339. EventRecord            gEvent;                    // currently pending event
  340. Boolean                gAllDone;                // true if the application is the in process of terminating
  341. Boolean                gInModalState;            // handling events with a modal dialog up
  342. MachineInfoRec        gMachineInfo;            // info about abilities and options installed on this machine
  343. short                gApplicationResFile;    // resource fork of application
  344. RgnHandle            gCursorRgn;                // region to control the cursor apearence
  345. #if !forCarbon
  346. AGRefNum            gAGRefNum = -1;            // AppleGuide database which is open
  347. FSSpec                gAGSpec;                // where to find our database
  348. AGCoachRefNum        gAGCoachRefNum = -1;    // coach handler refNum
  349. ThreadID            gAGThread;                // thread that looks for AppleGuide database
  350. #endif
  351. ThreadID            gFontThread;            // thread that builds font menu
  352. ThreadID            gStarterThread;            // starts our other threads for us
  353. Boolean                gDontYield;                // whether our threads should yield
  354. void*                gThreadResults;            // scratch space for thread results
  355. ComponentInstance        gOSAComponent = NULL;        // for AppleScript: connection to OSA scripting component
  356.  
  357. // AEC, addded
  358. ControlActionUPP    gVActionProc = NULL;
  359. ControlActionUPP    gHActionProc = NULL;
  360.  
  361. // These variables are for the find/replace commands
  362. Str255            gFindString = "\p", gReplaceString = "\p";
  363. Boolean            gWrapAround = false, gCaseSensitive = false;
  364.  
  365. // Metrowerks MWCRuntime.lib defines qd for us on PPC, and their
  366. // __runtime module does under the 68K case. OTOH, neither SC nor
  367. // MrC give us qd for free, so we need it there. I'm still not
  368. // certain which way to go for the ThinkC or Symantec PPC case.
  369. #if !defined(__MWERKS__)
  370. // QuickDraw globals
  371. //QDGlobals        qd;
  372. #endif
  373.  
  374. // --------------------------------------------------------------------------------------------------------------
  375. #pragma segment Utility
  376.  
  377. #if 0
  378. static pascal Boolean AlertFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  379. {
  380.     if (theEvent->what == activateEvt && (DialogPtr) theEvent->message == theDialog)
  381.         {
  382.         SetDialogDefaultItem(theDialog, 1);
  383.         }
  384.  
  385.     if (StdFilterProc(theDialog, theEvent, itemHit))
  386.         return true;
  387.  
  388.     // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
  389.     // drastically changing how the system handles the menu bar during our alert)
  390.     if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ )
  391.         {
  392.         HandleEvent(theEvent);
  393.         }
  394.  
  395.     return false;
  396.  
  397. } // AlertFilter
  398. #endif
  399.  
  400. void ConductErrorDialog(OSErr error, short commandID, short alertType)
  401. {
  402.     long        foundError;            // The error, converted to a number
  403.     short        stringIndex;        // Index into the strings
  404.     Str255        errorText;            // the error in a string format
  405.     
  406.     // Start with no error so far
  407.     foundError = 0;
  408.     
  409.     // Start with the first string
  410.     stringIndex = 1;
  411.     
  412.     // Loop until we find an error string
  413.     errorText[0] = 0;
  414.  
  415.     do
  416.         {
  417.         // Get the string, and convert it to a number
  418.         GetIndString(errorText, kErrorBaseID + commandID, stringIndex);
  419.         if (errorText[0] == 0)
  420.             break;
  421.         StringToNum(errorText, &foundError);
  422.         
  423.         // If we reach the last string, or we match the error code
  424.         if ((foundError == 0) ||
  425.             (foundError == error))
  426.             {
  427.             // Get the text string for this error
  428.             GetIndString(errorText, kErrorBaseID + commandID, stringIndex+1);
  429.             }
  430.         else
  431.             {
  432.             // Otherwise, make us continue until we get a string
  433.             errorText[0] = 0;
  434.             }
  435.             
  436.         // Advance so we get the next string number
  437.         stringIndex += 2;
  438.         
  439.         } while (errorText[0] == 0);                // errorText[0] == 0
  440.         
  441.     if (errorText[0] != 0)
  442.         {
  443.         DialogPtr    dPtr;
  444.         short        hit;
  445.         Cursor        arrow;
  446.         
  447.         SetCursor(GetQDGlobalsArrow(&arrow));
  448.         ParamText(errorText, "\p", "\p", "\p");
  449.         
  450.         dPtr = GetNewDialog(kErrorBaseID + alertType, nil, (WindowPtr)-1);
  451.         
  452.         SetDialogDefaultItem(dPtr, ok);
  453.         
  454.         BeginMovableModal();
  455.         
  456.         do
  457.             {
  458.             MovableModalDialog(nil, &hit);
  459.             } while (hit != ok);
  460.             
  461.         DisposeDialog(dPtr);
  462.         EndMovableModal();
  463.         }
  464.         
  465. } // ConductErrorDialog
  466.  
  467. // --------------------------------------------------------------------------------------------------------------
  468. #pragma segment Utility
  469.  
  470. static void MovableModalMenus(DialogPtr dPtr, short *pItem, long menuResult, long keyTime)
  471. {
  472.     short    iCut, iCopy, iClear, iPaste;
  473.     short    editMenu;
  474.     short    menuItem = menuResult & 0xFFFF;
  475.     
  476.     // find out where edit menus are
  477.     CommandToIDs(cCut, &editMenu, &iCut);
  478.     CommandToIDs(cCopy, &editMenu, &iCopy);
  479.     CommandToIDs(cClear, &editMenu, &iClear);
  480.     CommandToIDs(cPaste, &editMenu, &iPaste);
  481.     
  482.     UnhiliteMenuDelayed(keyTime);
  483.     switch (menuResult >> 16)
  484.         {
  485.         case mApple:
  486.             {
  487. #if(0)
  488.             Str255    tempString;
  489.             
  490.             GetMenuItemText(GetMenuHandle(menuResult>>16), menuItem, tempString);
  491.             OpenDeskAcc(tempString);
  492. #endif            
  493.             }
  494.             break;
  495.         case mEdit:
  496.             {
  497.             short    type;
  498.             Handle    item;
  499.             Rect    box;
  500.             short    editField = GetDialogKeyboardFocusItem(dPtr);
  501.             
  502.             // return typed item, if it isn't disabled
  503.             GetDialogItem(dPtr, editField, &type, &item, &box);
  504.             if ((type & itemDisable) == 0)
  505.                 *pItem = editField;
  506.                 
  507.             if (menuItem == iCut)
  508.                 {
  509.                 DialogCut(dPtr);
  510.                 ZeroScrap();
  511.                 TEToScrap();
  512.                 }
  513.                 
  514.             if (menuItem == iCopy)
  515.                 {
  516.                 DialogCopy(dPtr);
  517.                 ZeroScrap();
  518.                 TEToScrap();
  519.                 }
  520.                 
  521.             if (menuItem == iClear)
  522.                 DialogDelete(dPtr);
  523.                 
  524.             if (menuItem == iPaste)
  525.                 DialogPaste(dPtr);
  526.             }
  527.             break;
  528.         }
  529.         
  530. } // MovableModalMenus
  531.  
  532. // --------------------------------------------------------------------------------------------------------------
  533. #pragma segment Utility
  534.  
  535. void UnhiliteMenuDelayed(unsigned long keyTime)
  536. {
  537.     if (keyTime != 0)
  538.         {
  539.         keyTime = TickCount() - keyTime;
  540.         if (keyTime < kMenuHiliteDelay)
  541.             Delay(kMenuHiliteDelay - keyTime, &keyTime);
  542.         }
  543.     HiliteMenu(0);
  544. }
  545.  
  546. // --------------------------------------------------------------------------------------------------------------
  547. #pragma segment Utility
  548.  
  549. void MovableModalDialog(ModalFilterProcPtr filterProc, short *pItem)
  550. /*
  551.     Call this as you would ModalDialog, when the dialog is moveable
  552.     modal.
  553.     
  554.     However, first call BeginMovableModal, and afterwards (after
  555.     disposing of dialog) call EndMovableModal.
  556. */
  557. {
  558.     GrafPtr     curPort;
  559.     DialogPtr    dPtr = GetDialogFromWindow(FrontWindow());
  560.     RgnHandle    structRegion = NewRgn();
  561.  
  562.     *pItem = 0;
  563.     
  564.     if (dPtr)
  565.         {
  566.         GetPort(&curPort);
  567.                 SetPort(GetWindowPort(FrontWindow()));
  568.         
  569.         do
  570.             {
  571.             WaitNextEvent(mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + osMask,
  572.                             &gEvent, 0, nil);
  573.             
  574.             // call the filter proc
  575.             if ( (filterProc) && ((*filterProc) (dPtr, &gEvent, pItem)) )
  576.                 break;
  577.                             
  578.             // call the basic filtering
  579.             if (StdFilterProc(dPtr, &gEvent, pItem))
  580.                 break;
  581.                 
  582.             // handle keyboard
  583.             if ((gEvent.what == keyDown || gEvent.what == autoKey) && (gEvent.modifiers & cmdKey))
  584.                 {
  585.                 long    result;
  586.                 long    tck;
  587.                 
  588.                 result = MenuKey(gEvent.message & charCodeMask);
  589.                 tck = TickCount();
  590.                 
  591.                 MovableModalMenus(dPtr, pItem, result, tck);
  592.                 break;
  593.                 }
  594.                 
  595.             // handle clicks and drags
  596.             if (gEvent.what == mouseDown)
  597.                 {
  598.                 WindowPtr    whichWindow;
  599.                 short        part = FindWindow(gEvent.where, &whichWindow);
  600.                 DialogPtr    whichDialog = NULL;
  601.                 
  602.                 if (whichWindow)
  603.                     whichDialog = GetDialogFromWindow(whichWindow);
  604.  
  605.                 // menu bar events
  606.                 if (part == inMenuBar)
  607.                     {
  608.                     InitCursor();    // make sure we've got an arrow during menu tracking
  609.                     MovableModalMenus(dPtr, pItem, MenuSelect(gEvent.where), 0);
  610.                     break;
  611.                     }
  612.                     
  613.                 // check for outside of our window
  614.                 GetWindowRegion( GetDialogWindow( dPtr ), kWindowStructureRgn, structRegion );
  615.                 if (!PtInRgn(gEvent.where, structRegion))
  616.                     {
  617.                     SysBeep(1);
  618.                     gEvent.what = nullEvent;
  619.                     }
  620.                     
  621.                 // drag the window around
  622.                                 if ( (part == inDrag) && (whichDialog == dPtr) )
  623.                     {
  624.                     Rect    tempRect;
  625.                     
  626.                     DragWindow(whichWindow, gEvent.where, GetRegionBounds( GetGrayRgn(), &tempRect) );
  627.                     gEvent.what = nullEvent;
  628.                     }
  629.                 }
  630.                 
  631.             // check with standard dialog stuff    
  632.             {
  633.             DialogPtr    tempDialog;
  634.             
  635.             if ( IsDialogEvent(&gEvent) && DialogSelect(&gEvent, &tempDialog, pItem) )
  636.                 break;
  637.             }
  638.             
  639.             // handle updates
  640.             if (gEvent.what == updateEvt)
  641.                 {
  642.                 HandleEvent(&gEvent);
  643.                 break;
  644.                 }
  645.             } while (true);
  646.         
  647.         SetPort(curPort);
  648.         }
  649.         
  650. } // MovableModalDialog
  651.  
  652. // --------------------------------------------------------------------------------------------------------------
  653. #pragma segment Utility
  654.  
  655. void BeginMovableModal(void)
  656. {
  657.     DialogPtr    dPtr = GetDialogFromWindow(FrontWindow());
  658.     WindowPtr    nextWindow = GetNextWindow(FrontWindow());
  659.     
  660.     // Disable the current indicator because the upcoming dialog is moveable modal
  661.     HiliteMenu(0);
  662.         
  663.     if (nextWindow)
  664.         DoActivate(nextWindow, false);
  665.     AdjustMenus(GetDialogWindow(dPtr), (GetDialogKeyboardFocusItem(dPtr) > 0), false);
  666.  
  667. } // BeginMovableModal
  668.  
  669. // --------------------------------------------------------------------------------------------------------------
  670. #pragma segment Utility
  671.  
  672. void EndMovableModal(void)
  673. {
  674.     WindowPtr    nextWindow = FrontWindow();
  675.     
  676.     AdjustMenus(nextWindow, true, false);
  677.     if (nextWindow)
  678.         DoActivate(nextWindow, true);
  679.     
  680. } // EndMovableModal
  681.  
  682. // --------------------------------------------------------------------------------------------------------------
  683. #pragma segment Utility
  684.  
  685. short ConductFindOrReplaceDialog(short dialogID)
  686. {
  687.     DialogPtr    dPtr;
  688.     short        hit;
  689.     
  690.     // menu shouldn't stay hilighted during the dialog
  691.     HiliteMenu(0);
  692.     
  693.     dPtr = GetNewDialog(dialogID, nil, (WindowPtr)-1);
  694.     if (dPtr)
  695.         {
  696.         short    kind;
  697.         Rect    box;
  698.         Handle    item;
  699.         
  700.         // standard default behavior
  701.         SetDialogDefaultItem(dPtr, ok);
  702.         SetDialogCancelItem (dPtr, cancel);
  703.         SetDialogTracksCursor(dPtr, true);
  704.         
  705.         // Find string
  706.         GetDialogItem(dPtr, iFindEdit, &kind, &item, &box);
  707.         SetDialogItemText(item, gFindString);
  708.  
  709.         // check boxes
  710.         GetDialogItem(dPtr, iCaseSensitive, &kind, &item, &box);
  711.         SetControlValue((ControlHandle)item, gCaseSensitive);
  712.         GetDialogItem(dPtr, iWrapAround, &kind, &item, &box);
  713.         SetControlValue((ControlHandle)item, gWrapAround);
  714.         
  715.         if (dialogID == kReplaceWindowID)
  716.             {
  717.             // Replace string
  718.             GetDialogItem(dPtr, iReplaceEdit, &kind, &item, &box);
  719.             SetDialogItemText(item, gReplaceString);
  720.             }
  721.         
  722.         // select the search text by default
  723.         SelectDialogItemText(dPtr, iFindEdit, 0, 32767);
  724.         
  725.         // and away we go!
  726.         ShowWindow(GetDialogWindow(dPtr));
  727.         BeginMovableModal();
  728.         
  729.         do
  730.             {
  731.             MovableModalDialog(nil, &hit);
  732.             switch (hit)
  733.                 {
  734.                 case iCaseSensitive:
  735.                 case iWrapAround:
  736.                     GetDialogItem(dPtr, hit, &kind, &item, &box);
  737.                     SetControlValue((ControlHandle)item, 1-GetControlValue((ControlHandle)item));
  738.                     break;
  739.                 }
  740.             } while ( (hit != ok) && (hit != cancel) && (hit != iReplaceAll) );
  741.         
  742.         if (hit != cancel)
  743.             {
  744.             // Find string
  745.             GetDialogItem(dPtr, iFindEdit, &kind, &item, &box);
  746.             GetDialogItemText(item, gFindString);
  747.     
  748.             // nothing to find is like a cancel
  749.             if (gFindString[0] < 1)
  750.                 hit = cancel;
  751.                 
  752.             // check boxes
  753.             GetDialogItem(dPtr, iCaseSensitive, &kind, &item, &box);
  754.             gCaseSensitive = GetControlValue((ControlHandle)item);
  755.             GetDialogItem(dPtr, iWrapAround, &kind, &item, &box);
  756.             gWrapAround = GetControlValue((ControlHandle)item);
  757.             
  758.             if (dialogID == kReplaceWindowID)
  759.                 {
  760.                 // Replace string
  761.                 GetDialogItem(dPtr, iReplaceEdit, &kind, &item, &box);
  762.                 GetDialogItemText(item, gReplaceString);
  763.                 }
  764.             }
  765.             
  766.         DisposeDialog(dPtr);
  767.         EndMovableModal();
  768.         }
  769.         
  770.     return(hit);
  771.     
  772. } // ConductFindOrReplaceDialog
  773.  
  774. // --------------------------------------------------------------------------------------------------------------
  775. #pragma segment Utility
  776.  
  777. void LocalToGlobalRgn(RgnHandle rgn)
  778. {
  779.     Point        offset;
  780.     CGrafPtr    thePort = GetQDGlobalsThePort();
  781.     Rect bounds;
  782.  
  783.     GetPortBounds(thePort, &bounds);
  784.     offset = TopLeft(bounds);
  785.         
  786.     OffsetRgn(rgn, -offset.h, -offset.v);
  787.     
  788. } // LocalToGlobalRgn
  789.  
  790. // --------------------------------------------------------------------------------------------------------------
  791. #pragma segment Utility
  792.  
  793. void GlobalToLocalRgn(RgnHandle rgn)
  794. {
  795.     Point        offset;
  796.     CGrafPtr    thePort = GetQDGlobalsThePort();
  797.     Rect bounds;
  798.  
  799.     GetPortBounds(thePort, &bounds);
  800.  
  801.     offset = TopLeft(bounds);
  802.         
  803.     OffsetRgn(rgn, offset.h, offset.v);
  804.     
  805. } // GlobalToLocalRgn
  806.  
  807. // --------------------------------------------------------------------------------------------------------------
  808. #pragma segment Utility
  809.  
  810. void SetWatchCursor(void)
  811. {
  812.     CursHandle    theWatch;
  813.         
  814.     theWatch = MacGetCursor(watchCursor);
  815.     if (theWatch)
  816.         {
  817.         char    oldState;
  818.         
  819.         oldState = HGetState((Handle) theWatch);
  820.         HLock((Handle) theWatch);
  821.         SetCursor(*theWatch);
  822.         HSetState((Handle) theWatch, oldState);
  823.         }
  824.         
  825. } // SetWatchCursor
  826.  
  827. // --------------------------------------------------------------------------------------------------------------
  828. #pragma segment Utility
  829.  
  830. void LongRectToRect(LongRect* longRect, Rect *rect)
  831. {
  832.     rect->top         = longRect->top;
  833.     rect->left         = longRect->left;
  834.     rect->bottom     = longRect->bottom;
  835.     rect->right     = longRect->right;
  836.     
  837. } // LongRectToRect
  838.  
  839. // --------------------------------------------------------------------------------------------------------------
  840. #pragma segment Utility
  841.  
  842. void RectToLongRect(Rect *rect, LongRect *longRect)
  843. {
  844.     longRect->top         = rect->top;
  845.     longRect->left         = rect->left;
  846.     longRect->bottom     = rect->bottom;
  847.     longRect->right     = rect->right;
  848.     
  849. } // RectToLongRect
  850.  
  851. // --------------------------------------------------------------------------------------------------------------
  852. #pragma segment Utility
  853.  
  854. void GetPICTRectangleAt72dpi(PicHandle hPicture, Rect *pictureRect)
  855. {
  856.     typedef struct FixedRect {
  857.         Fixed left;
  858.         Fixed top;
  859.         Fixed right;
  860.         Fixed bottom;
  861.     } FixedRect;
  862.     
  863.     typedef struct {
  864.         Picture                pictInfo;
  865.         unsigned short        versionOp;        // 0x1101
  866.         Byte                opCodes[1];
  867.     } PICTHeaderVer1;
  868.     
  869.     typedef struct {
  870.         Picture            pictInfo;
  871.         unsigned short    versionOp;        // 0x0011
  872.         unsigned short    versionOp2;        // 0x02ff
  873.         unsigned short    headerOp;        // 0x0c00
  874.         unsigned short    version;        // 0xffff
  875.         unsigned short    version2;        // 0xffff
  876.         FixedRect        pictBounds;
  877.         unsigned long    reserved;
  878.         unsigned short    opCodes[1];
  879.     } PICTHeaderVer2;
  880.     
  881.     typedef struct {
  882.         Picture            pictInfo;
  883.         unsigned short    versionOp;        // 0x0011
  884.         unsigned short    versionOp2;        // 0x02ff
  885.         unsigned short    headerOp;        // 0x0c00
  886.         unsigned short    version;        // 0xfffe
  887.         unsigned short    reserved;        // 0x0000
  888.         Fixed            hRes;
  889.         Fixed            vRes;
  890.         Rect            pictBounds;
  891.         unsigned long    reserved2;
  892.         unsigned short    opCodes[1];
  893.     } PICTHeaderVer2Ext;
  894.  
  895.     Fixed            hRes, vRes;
  896.     PICTHeaderVer1* pPict = (PICTHeaderVer1*) *hPicture;
  897.     Rect            srcRect = (**hPicture).picFrame;
  898.  
  899.     hRes = vRes = ff(72);        // assume 72 dpi
  900.  
  901.     if (pPict->versionOp == 0x0011) 
  902.         {    
  903.         // Version 2 PICT
  904.     
  905.         PICTHeaderVer2* pPict2 = (PICTHeaderVer2*) pPict;
  906.         
  907.         if (pPict2->version == 0xfffe) 
  908.             {    
  909.             // Extended Version 2
  910.             PICTHeaderVer2Ext* pPict2ext = (PICTHeaderVer2Ext*) pPict;
  911.             hRes = pPict2ext->hRes;
  912.             vRes = pPict2ext->vRes;
  913.             srcRect = pPict2ext->pictBounds;
  914.             }
  915.         }
  916.  
  917.     hRes = FixDiv(hRes, ff(72));
  918.     vRes = FixDiv(vRes, ff(72));
  919.     pictureRect->left     = Fix2Long(FixDiv( ff(srcRect.left),     hRes ));
  920.     pictureRect->right     = Fix2Long(FixDiv( ff(srcRect.right),     hRes ));
  921.     pictureRect->top     = Fix2Long(FixDiv( ff(srcRect.top),     vRes ));
  922.     pictureRect->bottom = Fix2Long(FixDiv( ff(srcRect.bottom),     vRes ));
  923.     
  924. } // GetPICTRectangleAt72dpi
  925.  
  926. // --------------------------------------------------------------------------------------------------------------
  927. #pragma segment Utility
  928.  
  929. static WindowDataPtr    GetWindowInfo(WindowPtr pWindow)
  930. {
  931.     WindowDataPtr result = nil;
  932.     
  933.     if     (
  934.         (pWindow) &&
  935.         (GetWindowKind(pWindow) == userKind)
  936.         )
  937.         result = (WindowDataPtr) GetWRefCon(pWindow);
  938.  
  939.     return result;
  940.     
  941. } // GetWindowInfo
  942.  
  943. // --------------------------------------------------------------------------------------------------------------
  944. #pragma segment Utility
  945.  
  946. static short ZeroStringSub(Str255 destString, Str255 subStr)
  947.     // returns number of substitutions performed
  948. {
  949.     OSErr    anErr;
  950.     Handle    destHandle = nil;
  951.     Handle    subHandle = nil;
  952.     short    count = 0;
  953.  
  954.     anErr = PtrToHand(&destString[1], &destHandle, destString[0]);
  955.     if (anErr == noErr)
  956.         {        
  957.         anErr = PtrToHand(&subStr[1], &subHandle, subStr[0]);
  958.         if (anErr == noErr)
  959.             {
  960.             count = ReplaceText(destHandle, subHandle, "\p^0");        // error or # of substitutions
  961.                         
  962.             destString[0] = GetHandleSize(destHandle);
  963.             BlockMoveData(*destHandle, &destString[1], destString[0]);
  964.             }
  965.         }
  966.  
  967.     DisposeHandle(destHandle);
  968.     DisposeHandle(subHandle);
  969.  
  970.     if (count < 0)
  971.         count = 0;        // change error code into count = 0 substitutions
  972.  
  973.     return count;
  974.  
  975. } // ZeroStringSub
  976.  
  977. // --------------------------------------------------------------------------------------------------------------
  978. // BEGIN SCROLL ACTION PROCS
  979. // --------------------------------------------------------------------------------------------------------------
  980. #pragma segment Main
  981.  
  982. void SetControlAndClipAmount(ControlHandle control, short * amount)
  983. {
  984.     short        value, max;
  985.     
  986.     value = GetControlValue(control);    /* get current value */
  987.     max = GetControlMaximum(control);        /* and maximum value */
  988.     *amount = value - *amount;
  989.     if ( *amount < 0 )
  990.         *amount = 0;
  991.     else
  992.         {
  993.         if ( *amount > max )
  994.             *amount = max;
  995.         }
  996.     SetControlValue(control, *amount);
  997.     *amount = value - *amount;        /* calculate the real change */
  998.     
  999. } // SetControlAndClipAmount
  1000.  
  1001. // --------------------------------------------------------------------------------------------------------------
  1002. static pascal void VActionProc(ControlHandle control, short part)
  1003. {
  1004.     if (part != 0)
  1005.         {
  1006.                 WindowPtr        pWindow = GetControlOwner(control);
  1007.         WindowDataPtr         pData = GetWindowInfo(pWindow);
  1008.         short            amount = 0;
  1009.         
  1010.         switch (part)
  1011.             {
  1012.             case kControlUpButtonPart:
  1013.                 amount = pData->vScrollAmount;
  1014.                 SetControlAndClipAmount(control, &amount);
  1015.                 break;
  1016.                 
  1017.             case kControlDownButtonPart:
  1018.                 amount = -pData->vScrollAmount;
  1019.                 SetControlAndClipAmount(control, &amount);
  1020.                 break;
  1021.                 
  1022.             // vertical page scrolling should be a multiple of the incremental scrolling -- so that
  1023.             // we avoid half-lines of text at the bottom of pages.
  1024.             
  1025.             // More generically, if there was a method for dealing with text scrolling by a non-constant
  1026.             // amount, this would be better -- but SimpleText currently doesn't have a framework to allow
  1027.             // the document object to override the scroll amount dynamically.  Maybe something to add in
  1028.             // the future.
  1029.             case kControlPageUpPart:
  1030.                 amount = (((pData->contentRect.bottom - pData->contentRect.top) / pData->vScrollAmount)-1) * pData->vScrollAmount;
  1031.                 if (amount == 0)
  1032.                     amount = pData->contentRect.bottom - pData->contentRect.top;
  1033.                 SetControlAndClipAmount(control, &amount);
  1034.                 break;
  1035.  
  1036.             case kControlPageDownPart:
  1037.                 amount = (((pData->contentRect.top - pData->contentRect.bottom) / pData->vScrollAmount)+1) * pData->vScrollAmount;
  1038.                 if (amount == 0)
  1039.                     amount = pData->contentRect.top - pData->contentRect.bottom;
  1040.                 SetControlAndClipAmount(control, &amount);
  1041.                 break;
  1042.  
  1043.             default:
  1044.                 amount = pData->oldVValue - GetControlValue(control);
  1045.                 pData->oldVValue = GetControlValue(control);
  1046.                 break;
  1047.             }
  1048.         
  1049.         DoScrollContent(pWindow, pData, 0, amount);
  1050.         }
  1051.         
  1052. } // VActionProc
  1053.  
  1054.  
  1055. // --------------------------------------------------------------------------------------------------------------
  1056. static pascal void HActionProc(ControlHandle control, short part)
  1057. {
  1058.     if (part != 0)
  1059.         {
  1060.         WindowPtr        pWindow = GetControlOwner(control);
  1061.         WindowDataPtr         pData = GetWindowInfo(pWindow);
  1062.         short            amount = 0;
  1063.         
  1064.         switch (part)
  1065.             {
  1066.             case kControlUpButtonPart:
  1067.                 amount = pData->hScrollAmount;
  1068.                 SetControlAndClipAmount(control, &amount);
  1069.                 break;
  1070.                 
  1071.             case kControlDownButtonPart:
  1072.                 amount = -pData->hScrollAmount;
  1073.                 SetControlAndClipAmount(control, &amount);
  1074.                 break;
  1075.                 
  1076.             case kControlPageUpPart:
  1077.                 amount = pData->contentRect.right - pData->contentRect.left;
  1078.                 SetControlAndClipAmount(control, &amount);
  1079.                 break;
  1080.  
  1081.             case kControlPageDownPart:
  1082.                 amount = pData->contentRect.left - pData->contentRect.right;
  1083.                 SetControlAndClipAmount(control, &amount);
  1084.                 break;
  1085.  
  1086.             default:
  1087.                 amount = pData->oldHValue - GetControlValue(control);
  1088.                 pData->oldHValue = GetControlValue(control);
  1089.                 break;
  1090.             }
  1091.         
  1092.         DoScrollContent(pWindow, pData, amount, 0);
  1093.         }
  1094.         
  1095. } // HActionProc
  1096.  
  1097.  
  1098. // --------------------------------------------------------------------------------------------------------------
  1099. // END SCROLL ACTION PROCS
  1100. // --------------------------------------------------------------------------------------------------------------
  1101.  
  1102. // --------------------------------------------------------------------------------------------------------------
  1103. // SEARCH/REPLACE UTILITY FUNCTIONS
  1104. // --------------------------------------------------------------------------------------------------------------
  1105. static Boolean IsThisTheString(
  1106.             Ptr p,                        // pointer to check
  1107.             Str255 searchString,        // string to check for
  1108.             Boolean isCaseSensitive)    // case sensitive check or not
  1109. /*
  1110.     Returns true if the supplied string is at the specified offset.
  1111.     Otherwise returns false.
  1112. */
  1113. {
  1114.     Boolean    returnValue = false;
  1115.     
  1116.     if (isCaseSensitive)
  1117.         returnValue = ( IUMagString(p, &searchString[1], searchString[0], searchString[0]) == 0 );
  1118.     else
  1119.         returnValue = ( IUMagIDString(p, &searchString[1], searchString[0], searchString[0]) == 0 );
  1120.         
  1121.     return(returnValue);
  1122.     
  1123. } // IsThisTheString
  1124.  
  1125. // --------------------------------------------------------------------------------------------------------------
  1126.  
  1127. Boolean PerformSearch(
  1128.         Handle    h,                    // handle to search
  1129.         long start,                    // offset to begin with
  1130.         Str255 searchString,        // string to search for
  1131.         Boolean isCaseSensitive,    // case sensitive search
  1132.         Boolean isBackwards,        // search backwards from starting point
  1133.         Boolean isWraparound,        // wrap search around from end->begining
  1134.         long * pNewStart,            // returned new selection start
  1135.         long * pNewEnd)                // returned new selection end
  1136. /*
  1137.     Performs a search on the supplied handle, starting at the provided
  1138.     offset.  Returns the new selection start and end values, and true
  1139.     if the search is successful.  Otherwise it returns false.
  1140. */
  1141. {
  1142.     char    flags;
  1143.     Ptr        startPtr;
  1144.     Ptr        endPtr;
  1145.     Ptr        searchPtr;
  1146.     Boolean    foundIt = false;
  1147.     
  1148.     flags = HGetState(h);
  1149.     HLock(h);
  1150.             
  1151.     // back up one when searching backwards, or we'll hit every time on the current
  1152.     // character
  1153.     if (isBackwards)
  1154.         {
  1155.         if (start != 0)
  1156.             {
  1157.             --start;
  1158.             }
  1159.         else
  1160.             {
  1161.             if (isWraparound)
  1162.                 start = GetHandleSize(h);
  1163.             else
  1164.                 return(false);
  1165.             }
  1166.         }
  1167.         
  1168.     // determine the bounds of the searching
  1169.     startPtr = (*h) + start;
  1170.     if ( isWraparound )
  1171.         {
  1172.         if (isBackwards)
  1173.             {
  1174.             // go backwards until just after the start, or begining of
  1175.             // document is start is the end
  1176.             if (start == GetHandleSize(h))
  1177.                 endPtr = *h;
  1178.             else
  1179.                 endPtr = startPtr + 1;
  1180.             }
  1181.         else
  1182.             {
  1183.             // go forwards until just before the start, or to the end
  1184.             // of the document is the start is already the begining
  1185.             if (start == 0)
  1186.                 endPtr = *h + GetHandleSize(h);
  1187.             else
  1188.                 endPtr = startPtr - 1;
  1189.             }
  1190.         }
  1191.     else
  1192.         {
  1193.         if (isBackwards)
  1194.             {
  1195.             // go back until hit begining of document
  1196.             endPtr = *h-1;    
  1197.             }
  1198.         else
  1199.             {
  1200.             // go forward until hit end of document
  1201.             endPtr = *h + GetHandleSize(h);
  1202.             }
  1203.         }
  1204.         
  1205.     searchPtr = startPtr;
  1206.     while (searchPtr != endPtr)
  1207.         {
  1208.         short    byteType;
  1209.         
  1210.         byteType = CharacterByteType(startPtr, searchPtr - startPtr, smCurrentScript);
  1211.         
  1212.         if ( ((byteType == smSingleByte) || (byteType == smFirstByte)) &&
  1213.             IsThisTheString(searchPtr, searchString, isCaseSensitive)
  1214.             )
  1215.             {
  1216.             foundIt = true;
  1217.             *pNewStart = searchPtr - *h;
  1218.             *pNewEnd = *pNewStart + searchString[0];
  1219.             break;
  1220.             }
  1221.             
  1222.         if (isBackwards)
  1223.             --searchPtr;
  1224.         else
  1225.             ++searchPtr;
  1226.             
  1227.         if (isWraparound)
  1228.             {
  1229.             if (searchPtr < *h)
  1230.                 searchPtr = *h + GetHandleSize(h);
  1231.             if (searchPtr > *h + GetHandleSize(h))
  1232.                 searchPtr = *h;
  1233.             }
  1234.         }
  1235.         
  1236.     HSetState(h, flags);
  1237.     
  1238.     return(foundIt);
  1239.     
  1240. } // PerformSearch
  1241.  
  1242. // --------------------------------------------------------------------------------------------------------------
  1243. // SELECTION UTILITY ROUTINES
  1244. // --------------------------------------------------------------------------------------------------------------
  1245. void DrawSelection(WindowDataPtr pData, Rect *pSelection, short * pPhase, Boolean bumpPhase)
  1246. {
  1247.     if    (!EmptyRect(pSelection) ) 
  1248.         {
  1249.         RgnHandle    oldClip = NewRgn();
  1250.         Pattern        aPattern;
  1251.         Rect        newClip;
  1252.  
  1253.         
  1254.         if     ( 
  1255.             (bumpPhase) && 
  1256.             (MOVESELECTION(TickCount()) ) 
  1257.             )
  1258.             {
  1259.             if ((++(*pPhase)) > 7 )
  1260.                 *pPhase = 1;
  1261.             }
  1262.             
  1263.         // setup for drawing in this window
  1264.         SetPort((GrafPtr) pData);
  1265.         GetClip(oldClip);
  1266.         PenMode(notPatXor);
  1267.         
  1268.         // offset the draw area (SetOrigin a must to preserve pattern appearence)
  1269.         // and the clip area to avoid stepping on the scroll bars
  1270.         SetOrigin(GetControlValue(pData->hScroll), GetControlValue(pData->vScroll));
  1271.         newClip = pData->contentRect;
  1272.         OffsetRect(&newClip, GetControlValue(pData->hScroll), GetControlValue(pData->vScroll));
  1273.         ClipRect(&newClip);
  1274.         
  1275.         // do the draw
  1276.         GetIndPattern(&aPattern, kPatternListID, (*pPhase)+1);
  1277.         PenPat(&aPattern);
  1278.         FrameRect(pSelection);
  1279.         SetOrigin(0, 0);
  1280.         
  1281.         // restore the old port settings
  1282.         SetClip(oldClip);
  1283.         DisposeRgn(oldClip);
  1284.         PenNormal();
  1285.  
  1286.         }
  1287.  
  1288. } // DrawSelection
  1289.  
  1290. // --------------------------------------------------------------------------------------------------------------
  1291. OSErr SelectContents(WindowPtr pWindow, WindowDataPtr pData, EventRecord *pEvent, Rect *pSelection, Rect *pContent, short *pPhase)
  1292. {
  1293.  
  1294.     OSErr            anErr = noErr;
  1295.     Point            clickPoint = pEvent->where;
  1296.     Point            currentPoint;
  1297.     Boolean         didJustScroll;
  1298.     ControlHandle    theControl;
  1299.     
  1300.     GlobalToLocal(&clickPoint);
  1301.     if (FindControl(clickPoint, pWindow, &theControl) == 0)
  1302.         {
  1303.     
  1304.         // move the click point into the proper range
  1305.         clickPoint.h += GetControlValue(pData->hScroll);
  1306.         clickPoint.v += GetControlValue(pData->vScroll);
  1307.         
  1308.         // if the shift key is held down then the selection starts from
  1309.         // a preexisting point such that we are doing an expand/contract
  1310.         // of the original selection
  1311.         if (pEvent->modifiers & shiftKey)
  1312.             {
  1313.             if (clickPoint.h < pSelection->right)
  1314.                 clickPoint.h = pSelection->right;
  1315.             else
  1316.                 clickPoint.h = pSelection->left;
  1317.  
  1318.             if (clickPoint.v < pSelection->bottom)
  1319.                 clickPoint.v = pSelection->bottom;
  1320.             else
  1321.                 clickPoint.v = pSelection->top;
  1322.             }
  1323.                         
  1324.         while (StillDown())
  1325.             {                    
  1326.             CGrafPtr thePort = GetQDGlobalsThePort();
  1327.  
  1328.             // get the current mouse 
  1329.             GetMouse(¤tPoint);
  1330.             
  1331.             didJustScroll = false;
  1332.             // scroll contents if needed
  1333.             {
  1334.             short    deltaH = 0;
  1335.             short    deltaV = 0;
  1336.             Rect    bounds;
  1337.  
  1338.             GetPortBounds(thePort, &bounds);
  1339.             if (currentPoint.h < 0)
  1340.                 deltaH = pData->hScrollAmount;
  1341.                         if (currentPoint.h > bounds.right)
  1342.                 deltaH = -pData->hScrollAmount;
  1343.             if (currentPoint.v < 0)
  1344.                 deltaV = pData->vScrollAmount;
  1345.                         if (currentPoint.v > bounds.bottom)
  1346.                 deltaV = -pData->vScrollAmount;
  1347.                 
  1348.             if ( (deltaH != 0) || (deltaV != 0) )
  1349.                 {                
  1350.                 if (deltaH)
  1351.                     SetControlAndClipAmount(pData->hScroll, &deltaH);
  1352.                 if (deltaV)
  1353.                     SetControlAndClipAmount(pData->vScroll, &deltaV);
  1354.  
  1355.                 DoScrollContent(pWindow, pData, deltaH, deltaV);
  1356.                 
  1357.                 didJustScroll = true;
  1358.                 }
  1359.             }
  1360.             
  1361.             // map mouse into proper range
  1362.             currentPoint.h += GetControlValue(pData->hScroll);
  1363.             currentPoint.v += GetControlValue(pData->vScroll);
  1364.     
  1365.             // clip to the document size
  1366.             if (currentPoint.h < 0)
  1367.                 currentPoint.h = 0;
  1368.             if (currentPoint.v < 0)
  1369.                 currentPoint.v = 0;
  1370.             if (currentPoint.h > pContent->right)
  1371.                 currentPoint.h = pContent->right;
  1372.             if (currentPoint.v > pContent->bottom)
  1373.                 currentPoint.v = pContent->bottom;
  1374.                 
  1375.             // draw the new selection if it is time or we are about to 
  1376.             // exit this loop
  1377.             if ((MOVESELECTION(TickCount())) || (!Button()) || (didJustScroll) )
  1378.                 {
  1379.                 // first, erase any old selection we might have had
  1380.                 DrawSelection(pData, pSelection, pPhase, false);
  1381.  
  1382.                 // make a rectangle out of the two points
  1383.                 pSelection->left     = Min(currentPoint.h, clickPoint.h);
  1384.                 pSelection->right     = Max(currentPoint.h, clickPoint.h);
  1385.                 pSelection->top     = Min(currentPoint.v, clickPoint.v);
  1386.                 pSelection->bottom     = Max(currentPoint.v, clickPoint.v);
  1387.     
  1388.                 // draw the new selection
  1389.                 DrawSelection(pData, pSelection, pPhase, true);
  1390.                 }
  1391.             }
  1392.         
  1393.         // we handled the selection
  1394.         anErr = eActionAlreadyHandled;
  1395.         }
  1396.         
  1397.     return(anErr);
  1398.     
  1399. } // SelectContents
  1400.  
  1401. // --------------------------------------------------------------------------------------------------------------
  1402. void DragAndDropArea(WindowPtr pWindow, WindowDataPtr pData, EventRecord* event, Rect *pFrameRect)
  1403. {
  1404.     RgnHandle        hilightRgn;
  1405.     DragReference    theDrag;
  1406.     OSErr            anErr = noErr;
  1407.     
  1408.         
  1409.     if (NewDrag(&theDrag) == noErr)
  1410.         {
  1411.         
  1412.         // add the flavor for the window title, errors can be ignored as this
  1413.         // is a cosmetic addition
  1414.         {
  1415.         enum
  1416.             {
  1417.             kFlavorTypeClippingName = 'clnm'
  1418.             };
  1419.         Str255    windowTitle;
  1420.         
  1421.         GetWTitle(pWindow, windowTitle);
  1422.         (void)     AddDragItemFlavor(theDrag, 1, kFlavorTypeClippingName, &windowTitle, windowTitle[0]+1, flavorNotSaved);
  1423.         }
  1424.         
  1425.         if (pData->pDragAddFlavors)
  1426.             anErr = (*(pData->pDragAddFlavors)) (pWindow, pData, theDrag);
  1427.         
  1428.         if (anErr == noErr)
  1429.             {
  1430.             Rect    globalRect = *pFrameRect;
  1431.             
  1432.             hilightRgn = NewRgn();    
  1433.             LocalToGlobal(&TopLeft(globalRect));
  1434.             LocalToGlobal(&BotRight(globalRect));
  1435.             RectRgn(hilightRgn, &globalRect);
  1436.             SetDragItemBounds(theDrag, 1, &globalRect);
  1437.     
  1438.             // turn the region from a fill into a frame
  1439.             {    
  1440.                 RgnHandle tempRgn = NewRgn();
  1441.     
  1442.                 CopyRgn(hilightRgn, tempRgn);
  1443.                 InsetRgn(tempRgn, 1, 1);
  1444.                 DiffRgn(hilightRgn, tempRgn, hilightRgn);
  1445.                 DisposeRgn(tempRgn);
  1446.             }
  1447.             
  1448.             TrackDrag(theDrag, event, hilightRgn);
  1449.             DisposeDrag(theDrag);
  1450.             DisposeRgn(hilightRgn);
  1451.             }
  1452.         }
  1453.  
  1454. } // DragAndDropArea
  1455.  
  1456. // --------------------------------------------------------------------------------------------------------------
  1457. // WINDOW UTILITY ROUTINES
  1458. // --------------------------------------------------------------------------------------------------------------
  1459. #pragma segment Main
  1460.  
  1461. static void CalculateGrowIcon(WindowPtr pWindow,WindowDataPtr pData, Rect * location)
  1462. {
  1463. #pragma unused (pWindow)
  1464.  
  1465.     Rect bounds;
  1466.  
  1467.     if (pData->vScroll) {
  1468.             GetControlBounds(pData->vScroll, &bounds);
  1469.         location->top = bounds.bottom;
  1470.     } else {
  1471.         if (pData->hScroll) {
  1472.                         GetControlBounds(pData->hScroll, &bounds);
  1473.                         location->top = bounds.top;
  1474.         } else {
  1475.             GetWindowPortBounds(pData->theWindow, &bounds);
  1476.             location->top = bounds.bottom - 15;
  1477.         }
  1478.     }
  1479.         
  1480.     if (pData->hScroll) {
  1481.                 GetControlBounds(pData->hScroll, &bounds);
  1482.                 location->left = bounds.right;
  1483.     } else {
  1484.         if (pData->vScroll) {
  1485.                        GetControlBounds(pData->vScroll, &bounds);
  1486.             location->left = bounds.left;
  1487.         } else {
  1488.                         GetWindowPortBounds(pData->theWindow, &bounds);
  1489.                         location->left = bounds.right - 15;
  1490.             }
  1491.     }
  1492.  
  1493.     location->right = location->left + 16;
  1494.     location->bottom = location->top + 16;
  1495.     
  1496. } // CalculateGrowIcon
  1497.  
  1498. // --------------------------------------------------------------------------------------------------------------
  1499. #pragma segment Main
  1500.  
  1501. //
  1502. // Set the modified bit for the window
  1503. //
  1504. void SetDocumentContentChanged( WindowDataPtr pData, Boolean changed )
  1505. {
  1506.     pData->changed = changed;
  1507.         
  1508.     if( gMachineInfo.haveProxyIcons )
  1509.         SetWindowModified( pData->theWindow, changed );
  1510.  
  1511. }
  1512.  
  1513.  
  1514. // --------------------------------------------------------------------------------------------------------------
  1515. #pragma segment Main
  1516.  
  1517. OSErr    AdjustScrollBars(WindowRef pWindow,
  1518.     Boolean moveControls,                 // might the controls have moved?
  1519.     Boolean didResize,                     // did we just resize the window?
  1520.     Boolean *needInvalidate)            // does the caller need to invalidate contents as a result?
  1521. {
  1522.     OSErr            anErr = noErr;
  1523.     LongRect        docRect;
  1524.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  1525.     Rect            growIconRect;
  1526.     
  1527.     if (needInvalidate)
  1528.         *needInvalidate = false;
  1529.  
  1530.     if (pData)
  1531.         {
  1532.         short    oldHMax = 0;
  1533.         short    oldVMax = 0;
  1534.         short    oldHValue = 0;
  1535.         short    oldVValue = 0;
  1536.                 Rect bounds;
  1537.         
  1538.         // cache current values, we'll force an update if we needed to change em!
  1539.         if (pData->hScroll)
  1540.             {
  1541.             oldHMax = GetControlMaximum(pData->hScroll);
  1542.             oldHValue = GetControlValue(pData->hScroll);
  1543.             }
  1544.         if (pData->vScroll)
  1545.             {
  1546.             oldVMax = GetControlMaximum(pData->vScroll);
  1547.             oldVValue = GetControlValue(pData->vScroll);
  1548.             }
  1549.             
  1550.         // if we have a grow box but not all controls we have to invalidate the grow bar areas
  1551.         // by caclulating them
  1552.         if ( (didResize) && (pData->hasGrow) )
  1553.             {
  1554.                         GetWindowPortBounds(pWindow, &bounds);
  1555.  
  1556.             // if we regrow without any scroll bars, we need to update the content area
  1557.             if ( (needInvalidate) && (pData->hScroll == nil) && (pData->vScroll == nil) )
  1558.                 *needInvalidate = true;
  1559.             
  1560.             // invalidate old grow bar areas
  1561.             if (pData->vScroll == nil)
  1562.                 {
  1563.                 growIconRect = bounds;
  1564.                 growIconRect.left = pData->contentRect.right;
  1565.                 InvalWindowRect(pWindow,&growIconRect);
  1566.                 }
  1567.             if (pData->hScroll == nil)
  1568.                 {
  1569.                                 growIconRect = bounds;
  1570.                 growIconRect.top = pData->contentRect.bottom;
  1571.                 InvalWindowRect(pWindow,&growIconRect);
  1572.                 }
  1573.             
  1574.             // invalidate new grow bar areas
  1575.             if (pData->vScroll == nil)
  1576.                 {
  1577.                                 growIconRect = bounds;
  1578.                 growIconRect.left = growIconRect.right - kScrollBarSize;
  1579.                 InvalWindowRect(pWindow,&growIconRect);
  1580.                 }
  1581.             if (pData->hScroll == nil)
  1582.                 {
  1583.                                 growIconRect = bounds;
  1584.                 growIconRect.top = growIconRect.bottom - kScrollBarSize;
  1585.                 InvalWindowRect(pWindow,&growIconRect);
  1586.                 }
  1587.             }
  1588.             
  1589.         // if the controls need moving, recalculate the visible area
  1590.         if (moveControls)
  1591.             {
  1592.                         growIconRect = bounds;
  1593.             if ((pData->hScroll) || (pData->hasGrow) )
  1594.                 pData->contentRect.bottom -= kScrollBarSize;
  1595.             if ((pData->vScroll) || (pData->hasGrow) )
  1596.                 pData->contentRect.right -= kScrollBarSize;
  1597.             }
  1598.             
  1599.         // before doing anything, make the controls invisible
  1600.         if (pData->hScroll)
  1601.                     SetControlVisibility(pData->hScroll, false, false);
  1602.         if (pData->vScroll)
  1603.                     SetControlVisibility(pData->vScroll, false, false);
  1604.  
  1605.         // based on document and visiable area, adjust possible control values
  1606.         if ( (pData->pGetDocumentRect) && ((pData->hScroll) || (pData->vScroll)) )
  1607.             {
  1608.             // let the object calc the size and content if it wishes to
  1609.             anErr = (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, false);
  1610.             if (anErr == noErr)
  1611.                 {
  1612.                 short    amountOver;
  1613.                 short    newMax;
  1614.                 
  1615.                 amountOver = (docRect.right - docRect.left) - (pData->contentRect.right - pData->contentRect.left);
  1616.                 if     (
  1617.                     (pData->hScroll) &&
  1618.                     (amountOver > 0)
  1619.                     )
  1620.                     newMax = amountOver;
  1621.                 else
  1622.                     newMax = 0;
  1623.     
  1624.                 if (pData->hScroll)
  1625.                     {
  1626.                     if (GetControlValue(pData->hScroll) > newMax)
  1627.                         {
  1628.                         if (needInvalidate)
  1629.                             *needInvalidate = true;
  1630.                         }
  1631.                     SetControlMaximum(pData->hScroll, newMax);
  1632.                     }
  1633.                 
  1634.                 amountOver = (docRect.bottom - docRect.top) - (pData->contentRect.bottom - pData->contentRect.top);
  1635.                 if     (
  1636.                     (pData->vScroll) &&
  1637.                     (amountOver > 0)
  1638.                     )
  1639.                     newMax = amountOver;
  1640.                 else
  1641.                     newMax = 0;
  1642.                     
  1643.                 if (pData->vScroll)
  1644.                     {
  1645.                     if (GetControlValue(pData->vScroll) > newMax)
  1646.                         {
  1647.                         if (needInvalidate)
  1648.                             *needInvalidate = true;
  1649.                         }
  1650.                     SetControlMaximum(pData->vScroll, newMax);
  1651.                     }
  1652.                 }
  1653.             }
  1654.             
  1655.         // then, if the controls need moving, we move them and inval the old
  1656.         // and new locations
  1657.         if (moveControls)
  1658.             {
  1659.             // if we have grow box we invalidate the old grow location
  1660.             if ( pData->hasGrow) 
  1661.                 {
  1662.                 CalculateGrowIcon(pWindow, pData, &growIconRect);
  1663.                 InvalWindowRect(pWindow,&growIconRect);
  1664.                 }
  1665.                 
  1666.             if (pData->hScroll)
  1667.                 {
  1668.                 short    widthAdjust;
  1669.                 Rect bounds;
  1670.                 
  1671.                 if ((pData->vScroll) || (pData->hasGrow))
  1672.                     widthAdjust = -kGrowScrollAdjust;
  1673.                 else
  1674.                     widthAdjust = -1;
  1675.                     
  1676.                 GetControlBounds(pData->hScroll, &bounds);
  1677.                 InvalWindowRect( pWindow, &bounds);
  1678.  
  1679.                 GetWindowPortBounds(pWindow, &bounds);
  1680.                                 MoveControl(pData->hScroll, pData->hScrollOffset - 1, bounds.bottom - kScrollBarSize);
  1681.                                 SizeControl(pData->hScroll, (bounds.right - bounds.left) + widthAdjust - pData->hScrollOffset, 16);
  1682.  
  1683.                                 GetControlBounds(pData->hScroll, &bounds);
  1684.                                 InvalWindowRect( pWindow, &bounds);
  1685.                 }
  1686.  
  1687.             if (pData->vScroll)
  1688.                 {
  1689.                 short    heightAdjust;
  1690.                 
  1691.                 if ((pData->hScroll) || (pData->hasGrow))
  1692.                     heightAdjust = -kGrowScrollAdjust;
  1693.                 else
  1694.                     heightAdjust = -1;
  1695.                     
  1696.                 GetControlBounds(pData->vScroll, &bounds);
  1697.                                 InvalWindowRect( pWindow, &bounds);
  1698.  
  1699.                                 GetWindowPortBounds(pWindow, &bounds);
  1700.                                 MoveControl(pData->vScroll, bounds.right - kScrollBarSize, pData->vScrollOffset-1);
  1701.                                 SizeControl(pData->vScroll, 16, (bounds.bottom - bounds.top) + heightAdjust - pData->vScrollOffset);
  1702.  
  1703.                                 GetControlBounds(pData->vScroll, &bounds);
  1704.                                 InvalWindowRect( pWindow, &bounds);
  1705.                 }
  1706.                 
  1707.             // if we have scroll bars, update the grow icon
  1708.             if ( pData->hasGrow )
  1709.                 {
  1710.                 CalculateGrowIcon(pWindow,pData, &growIconRect);
  1711.                 InvalWindowRect(pWindow,&growIconRect);
  1712.                 }
  1713.             
  1714.             }
  1715.  
  1716.         // let the document adjust anything it needs to
  1717.         if (pData->pAdjustSize)
  1718.             anErr = (*(pData->pAdjustSize)) (pWindow, pData, &didResize);
  1719.             
  1720.         if ((didResize) && (needInvalidate))
  1721.             *needInvalidate = true;
  1722.  
  1723.  
  1724.                 if ( IsWindowHilited(pWindow) )
  1725.             {
  1726.             // after doing something, make the controls visible
  1727.             if (pData->hScroll)
  1728.                 {
  1729.                 if ((oldHMax != GetControlMaximum(pData->hScroll)) || (oldHValue != GetControlValue(pData->hScroll)) )
  1730.                                     ShowControl(pData->hScroll);
  1731.                 else
  1732.                                     SetControlVisibility(pData->hScroll, true, false);    
  1733.                 }
  1734.             if (pData->vScroll)
  1735.                 {
  1736.                 if ((oldVMax != GetControlMaximum(pData->vScroll)) || (oldVValue != GetControlValue(pData->vScroll)) )
  1737.                     ShowControl(pData->vScroll);
  1738.                 else
  1739.                                     SetControlVisibility(pData->vScroll, true, false);    
  1740.                 }
  1741.             }
  1742.  
  1743.         }
  1744.         
  1745.     return anErr;
  1746.     
  1747. } // AdjustScrollBars
  1748.  
  1749. // --------------------------------------------------------------------------------------------------------------
  1750. // MENU UTILITY ROUTINES
  1751. // --------------------------------------------------------------------------------------------------------------
  1752. #pragma segment Main
  1753.  
  1754. Boolean CommandToIDs(short commandID, short * menuID, short *itemID)
  1755. {
  1756.  
  1757.     short    ** commandHandle;
  1758.     short    whichMenu;
  1759.     short    oldResFile = CurResFile();
  1760.     Boolean    returnValue = false;
  1761.     
  1762.     UseResFile(gApplicationResFile);
  1763.     for (whichMenu = mApple; whichMenu <= mLastMenu; whichMenu++)
  1764.         {
  1765.         commandHandle = (short**) Get1Resource('MCMD', whichMenu);
  1766.         if (commandHandle)
  1767.             {
  1768.             short    * pCommands = *commandHandle;
  1769.             short    commandIndex;
  1770.             short    numCommands = pCommands[0];
  1771.             
  1772.             for (commandIndex = 1; commandIndex <= numCommands; ++commandIndex)
  1773.                 if (pCommands[commandIndex] == commandID)
  1774.                     {
  1775.                     *menuID = whichMenu;
  1776.                     *itemID = commandIndex;
  1777.                     
  1778.                     returnValue = (commandIndex == numCommands);
  1779.                     }
  1780.             }    
  1781.         }
  1782.         
  1783.     UseResFile(oldResFile);
  1784.     
  1785.     return returnValue;
  1786.     
  1787. } // CommandToIDs
  1788.  
  1789. // --------------------------------------------------------------------------------------------------------------
  1790. #pragma segment Main
  1791.  
  1792. Boolean IsCommandEnabled(short commandID)
  1793. /*
  1794.     returns true if a given command is currently enabled
  1795. */
  1796. {
  1797.     short        whichMenu, whichItem;
  1798.     MenuHandle    menu;
  1799.     
  1800.     CommandToIDs(commandID, &whichMenu, &whichItem);
  1801.     menu = GetMenuHandle(whichMenu);
  1802.     
  1803.         if (IsMenuItemEnabled(menu, whichItem))
  1804.         return(true);
  1805.     
  1806.     return(false);
  1807.     
  1808. } // IsCommandEnabled
  1809.  
  1810. // --------------------------------------------------------------------------------------------------------------
  1811. #pragma segment Main
  1812.  
  1813. void EnableCommand(short commandID)
  1814. /*
  1815.     Given a command ID, enables the first menu item with that command ID.
  1816.     
  1817.     If the command table for a given menu is less than the number of items in the menu,
  1818.     and the command being enabled is the last item in the command table, then all
  1819.     items from there on down are also enabled.  This is useful for menus that get
  1820.     appended to, such as the desk accessory list, font list, or speaking voices list.
  1821. */
  1822. {
  1823.     short    whichMenu;
  1824.     short    whichItem;
  1825.     
  1826.     if (CommandToIDs(commandID, &whichMenu, &whichItem))
  1827.         {
  1828.         short        i;
  1829.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1830.         
  1831.         if (menu)
  1832.             {
  1833.             short        numItems = CountMItems(menu);
  1834.             
  1835.             for (i = whichItem; i <= numItems; ++i)
  1836.                 EnableMenuItem(menu, i);
  1837.             }
  1838.         }
  1839.     else
  1840.         {
  1841.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1842.  
  1843.         if (menu)
  1844.             EnableMenuItem(menu, whichItem);
  1845.         }
  1846.         
  1847. } // EnableCommand
  1848.  
  1849. // --------------------------------------------------------------------------------------------------------------
  1850. #pragma segment Main
  1851.  
  1852. void ChangeCommandName(short commandID, short resourceID, short resourceIndex)
  1853. {
  1854.     short        whichMenu;
  1855.     short        whichItem;
  1856.     MenuHandle    menu;
  1857.     
  1858.     // figure out how this command maps into the menu bar
  1859.     CommandToIDs(commandID, &whichMenu, &whichItem);
  1860.     menu = GetMenuHandle(whichMenu);
  1861.     
  1862.     // then make this item into the requested new string
  1863.     {
  1864.     Str255        theString;
  1865.     
  1866.     GetIndString(theString, resourceID, resourceIndex);
  1867.     SetMenuItemText(menu, whichItem, theString);
  1868.     }
  1869.     
  1870. } // ChangeCommandName
  1871.  
  1872. // --------------------------------------------------------------------------------------------------------------
  1873. #pragma segment Main
  1874.  
  1875. void EnableCommandCheck(short commandID, Boolean check)
  1876. {
  1877.  
  1878.     short    whichMenu;
  1879.     short    whichItem;
  1880.     
  1881.     if (CommandToIDs(commandID, &whichMenu, &whichItem))
  1882.         {
  1883.         short        i;
  1884.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1885.         short        numItems = CountMItems(menu);
  1886.         
  1887.         for (i = whichItem; i <= numItems; ++i)
  1888.             {
  1889.             EnableMenuItem(menu, i);
  1890.             CheckItem(menu, i, check);
  1891.             }
  1892.         }
  1893.     else
  1894.         {
  1895.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1896.  
  1897.         EnableMenuItem(menu, whichItem);
  1898.         CheckItem(menu, whichItem, check);
  1899.         }
  1900.         
  1901. } // EnableCommandCheck
  1902.  
  1903.  
  1904. // --------------------------------------------------------------------------------------------------------------
  1905. #pragma segment Main
  1906.  
  1907. void EnableCommandCheckStyle(short commandID, Boolean check, short style)
  1908. {
  1909.  
  1910.     short    whichMenu;
  1911.     short    whichItem;
  1912.     
  1913.     if (CommandToIDs(commandID, &whichMenu, &whichItem))
  1914.         {
  1915.         short        i;
  1916.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1917.         short        numItems = CountMItems(menu);
  1918.         
  1919.         for (i = whichItem; i <= numItems; ++i)
  1920.             {
  1921.             EnableMenuItem(menu, i);
  1922.             CheckItem(menu, i, check);
  1923.             SetItemStyle(menu, i, style);
  1924.             }
  1925.         }
  1926.     else
  1927.         {
  1928.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1929.  
  1930.         EnableMenuItem(menu, whichItem);
  1931.         CheckItem(menu, whichItem, check);
  1932.         SetItemStyle(menu, whichItem, style);
  1933.         }
  1934.         
  1935. } // EnableCommandCheckStyle
  1936.  
  1937. // --------------------------------------------------------------------------------------------------------------
  1938. #pragma segment Main
  1939.  
  1940. static     void    DisableEntireMenu(MenuHandle menu);        
  1941. static     void    DisableEntireMenu(MenuHandle menu)
  1942. {
  1943.     SInt16 i, count;
  1944.  
  1945.     count = CountMItems(menu);
  1946.  
  1947.     for (i = 0; i <= count; i++)
  1948.     {
  1949.             DisableMenuItem(menu, i);
  1950.     }
  1951. }
  1952.  
  1953. static Boolean IsAnyMenuItemEnabled(MenuHandle menu);
  1954. static Boolean IsAnyMenuItemEnabled(MenuHandle menu)
  1955. {
  1956.     SInt16 i, count;
  1957.  
  1958.     count = CountMItems(menu);
  1959.  
  1960.     for (i = 1; i <= count; i++)
  1961.     {
  1962.         if (IsMenuItemEnabled(menu, i))
  1963.         return(true);
  1964.     }
  1965.  
  1966.     return(false);
  1967. }
  1968.  
  1969. Boolean AdjustMenus(WindowPtr pWindow, Boolean editDialogs, Boolean forceTitlesOn)
  1970. {
  1971.     Boolean                 wasEnabled[mNumberMenus];    // Old state of menus
  1972.     MenuHandle                menus[mNumberMenus];
  1973.     short                    whichMenu;            // for stepping through menus
  1974.     MenuHandle                menu;                // for reading in menu IDs
  1975.     WindowDataPtr                 pData = GetWindowInfo(pWindow);
  1976.     
  1977.     // Step through all of the menus 
  1978.     for (whichMenu = mApple; whichMenu <= mLastMenu; whichMenu++)
  1979.         {
  1980.         // Save the old state of the menu title 
  1981.         menus[whichMenu - mApple] = menu = GetMenuHandle(whichMenu);
  1982.         if (menu)                                // because contents menu may not be around
  1983.             {
  1984.             if (forceTitlesOn)                
  1985.                 wasEnabled[mLastMenu - whichMenu] = false;
  1986.             else
  1987.                             wasEnabled[mLastMenu - whichMenu] = IsMenuItemEnabled(menu, 0);
  1988.             
  1989.             // Disable the entire menu 
  1990.             DisableEntireMenu(menu);        
  1991.             }
  1992.         }
  1993.     
  1994.     // select all, unless someone else changes it
  1995.     ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand);
  1996.  
  1997.     // if we have NO windows, or the current window is one we understand
  1998.     if ((pWindow == nil) || (pData))
  1999.         {
  2000.         // enable the default commands
  2001.         EnableCommand(cAbout);
  2002.         EnableCommand(cDeskAccessory);
  2003.         
  2004.         EnableCommand(cNew);
  2005.         EnableCommand(cOpen);
  2006.         EnableCommand(cQuit);
  2007.     
  2008.         EnableCommand(cShowClipboard);
  2009.         }
  2010.     else
  2011.         {
  2012.         // it's printing or a dialog, so enable cut/copy/paste
  2013.         if (editDialogs)
  2014.             {
  2015.             EnableCommand(cCut);
  2016.             EnableCommand(cCopy);
  2017.             EnableCommand(cPaste);
  2018.             EnableCommand(cClear);
  2019.             }
  2020.         
  2021.         // and desk accs too!        
  2022.         EnableCommand(cDeskAccessory);
  2023.  
  2024.         }
  2025.         
  2026.     if ( (pWindow) && (pData) )
  2027.         {
  2028.         // all windows can be closed
  2029.         if (FrontWindow())
  2030.             EnableCommand(cClose);
  2031.  
  2032.         // changed documents can be saved, but only if the file is open for write
  2033.         if (     (pData->changed) && 
  2034.                 ((pData->isWritable) || (pData->dataRefNum == -1)) )
  2035.             EnableCommand(cSave);
  2036.         
  2037.         // objects with a print method can be printed and page setup-ed
  2038.         if (pData->pPrintPage)
  2039.             {
  2040.             EnableCommand(cPrint);
  2041.             EnableCommand(cPageSetup);
  2042.             EnableCommand(cPrintOneCopy);
  2043.             }
  2044.             
  2045.         // let object enable anything else that needs to be enabled
  2046.         if (pData->pAdjustMenus)
  2047.             (*(pData->pAdjustMenus)) (pWindow, pData);
  2048.         }
  2049.         
  2050.     // Now determine if any of the menus have changed state
  2051.     {
  2052.     Boolean gotToRedraw = false;
  2053.     
  2054.     for (whichMenu = mApple; whichMenu <= mLastMenu; ++whichMenu)
  2055.         {
  2056.         menu = menus[whichMenu - mApple];
  2057.     
  2058.         if (menu)        // because contents menu may not be around
  2059.             {
  2060.             // If any of the menu is enabled
  2061.                         if (IsAnyMenuItemEnabled(menu))
  2062.                 {
  2063.                 // Make sure to turn on the menu title
  2064.                                 EnableMenuItem(menu, 0);
  2065.                 }
  2066.                 
  2067.             /*     If this new state is different than the saved state, then the menu bar
  2068.                 will need to be redrawn */
  2069.             if (wasEnabled[mLastMenu - whichMenu] != IsMenuItemEnabled(menu, 0))
  2070.                 {
  2071.                 gotToRedraw = true;
  2072.                 }
  2073.             }
  2074.         }
  2075.         
  2076.     // And if any titles have changed state, redraw them 
  2077.     if (gotToRedraw)
  2078.         DrawMenuBar();
  2079.         
  2080.     return gotToRedraw;
  2081.     }
  2082.         
  2083. } // AdjustMenus
  2084.  
  2085. // --------------------------------------------------------------------------------------------------------------
  2086. // FILE UTILITY ROUTINES
  2087. // --------------------------------------------------------------------------------------------------------------
  2088. #pragma segment Utility
  2089.  
  2090. static Boolean BringToFrontIfOpen(FSSpecPtr pSpec)
  2091. {
  2092.     WindowPtr        pWindow;
  2093.     
  2094.     pWindow = FrontWindow();
  2095.     while (pWindow)
  2096.         {
  2097.         WindowDataPtr pData = GetWindowInfo(pWindow);
  2098.         
  2099.         if (
  2100.             (pData) &&
  2101.             (pData->fileSpec.vRefNum == pSpec->vRefNum) &&
  2102.             (pData->fileSpec.parID == pSpec->parID) &&
  2103.             EqualString(pData->fileSpec.name, pSpec->name, false, false)
  2104.             )
  2105.             {
  2106.             SelectWindow(pWindow);
  2107.             return true;
  2108.             }
  2109.             
  2110.         pWindow = GetNextWindow(pWindow);
  2111.         }
  2112.         
  2113.     return false;
  2114.     
  2115. } // BringToFrontIfOpen
  2116.  
  2117. // --------------------------------------------------------------------------------------------------------------
  2118. #pragma segment Utility
  2119.  
  2120. static Boolean BringToFrontIfExists(ResType windowKind)
  2121. {
  2122.     WindowPtr        pWindow;
  2123.     
  2124.     pWindow = FrontWindow();
  2125.     while (pWindow)
  2126.         {
  2127.         WindowDataPtr pData = GetWindowInfo(pWindow);
  2128.         
  2129.         if ((pData) && (pData->windowKind == windowKind))
  2130.             {
  2131.             SelectWindow(pWindow);
  2132.             return true;
  2133.             }
  2134.             
  2135.         pWindow = GetNextWindow(pWindow);
  2136.         }
  2137.         
  2138.     return false;
  2139.     
  2140. } // BringToFrontIfExists
  2141.  
  2142. // --------------------------------------------------------------------------------------------------------------
  2143. // MAIN SIMPLETEXT ROUTINES
  2144. // --------------------------------------------------------------------------------------------------------------
  2145. #pragma segment Main
  2146.  
  2147. static OSErr MakeNewWindow(ResType windowKind, FSSpecPtr fileSpec, OSType fileType, Boolean *pWasAlreadyOpen)
  2148. {
  2149.     OSErr                anErr = fnfErr;
  2150.     PreflightRecord        thePreflight;
  2151.     PreflightWindowProc    pPreflight = nil;
  2152.     WindowPtr            pWindow;
  2153.     WindowDataPtr        pData;
  2154.     ControlHandle        rootControl;
  2155.     
  2156.     // require a certain amount of RAM free before we allow the new window to be created
  2157.     if (FreeMem() < kRAMNeededForNew)
  2158.         anErr = memFullErr;
  2159.         
  2160.     // make sure we update the cursor
  2161.     SetEmptyRgn(gCursorRgn);
  2162.     
  2163.     // <50> if we already have a document open from this file, bring the window to the
  2164.     // front and return with no error
  2165.     if ( (fileSpec) && (fileType != 'sEXT') && (BringToFrontIfOpen(fileSpec)) )
  2166.         {
  2167.         if (pWasAlreadyOpen)
  2168.             *pWasAlreadyOpen = true;
  2169.         anErr = noErr;
  2170.         return(anErr);
  2171.         }
  2172.     if (pWasAlreadyOpen)
  2173.         *pWasAlreadyOpen = false;
  2174.     if (anErr != fnfErr)
  2175.         {
  2176.         nrequire(anErr, SanityCheckFailed);
  2177.         }
  2178.         
  2179.     // initialize our behavior
  2180.     thePreflight.continueWithOpen     = true;
  2181.     thePreflight.resourceID         = kDefaultWindowID;
  2182.     thePreflight.wantHScroll         = false;
  2183.     thePreflight.wantVScroll         = false;
  2184.     thePreflight.storageSize         = sizeof(WindowDataRecord);
  2185.     thePreflight.makeProcPtr         = nil;
  2186.     thePreflight.openKind            = fsRdPerm;
  2187.     thePreflight.needResFork        = false;
  2188.     thePreflight.doZoom                = false;
  2189.     thePreflight.fileType            = fileType;
  2190.     
  2191.     switch (windowKind)
  2192.         {
  2193.         case kAboutWindow:
  2194.             pPreflight = AboutPreflightWindow;
  2195.             break;
  2196.  
  2197.         case kPICTWindow:
  2198.             pPreflight = PICTPreflightWindow;
  2199.             break;
  2200.  
  2201. #if ALLOW_QUICKTIME
  2202.         case kMovieWindow:
  2203.             pPreflight = MoviePreflightWindow;
  2204.             break;
  2205. #endif
  2206.  
  2207.         case kClipboardWindow:
  2208.             pPreflight = ClipboardPreflightWindow;
  2209.             break;
  2210.  
  2211.         case kTextWindow:
  2212.             pPreflight = TextPreflightWindow;
  2213.             break;
  2214.  
  2215. #if ALLOW_QUICKTIME
  2216.         case kThreeDWindow:
  2217.             pPreflight = ThreeDPreflightWindow;
  2218.             break;
  2219. #endif
  2220.         }
  2221.     
  2222.     // preflight the window    
  2223.     if (pPreflight)
  2224.         anErr = (*pPreflight) (&thePreflight);
  2225.     nrequire(anErr, PreflightFailed);
  2226.     
  2227.     if (thePreflight.continueWithOpen)
  2228.         {
  2229.         // allocate a place for the window
  2230.         pData = (WindowDataPtr)NewPtrClear(thePreflight.storageSize);
  2231.         anErr = MemError();
  2232.         nrequire(anErr, FailedToAllocateWindow);
  2233.         
  2234.         // then actually create the window
  2235.         pWindow = GetNewCWindow(thePreflight.resourceID, NULL, (WindowPtr)-1);
  2236.         if (!pWindow) anErr = memFullErr;
  2237.         nrequire(anErr, NewWindowFailed);
  2238.  
  2239.         pData->theWindow = pWindow;
  2240.         SetWRefCon(pWindow, (long) pData);
  2241.                 
  2242.         if (gMachineInfo.haveAppearanceMgr)
  2243.             CreateRootControl(pWindow, &rootControl);
  2244.                 
  2245.         // zoom the rectangle to big size on this monitor 
  2246.         // based upon which scroll bars they want
  2247.         {
  2248.         Rect    rect;
  2249.         Rect    bigRect;
  2250.  
  2251.         GetWindowPortBounds(pWindow, &rect);
  2252.         bigRect = (**GetMainDevice()).gdRect;
  2253.  
  2254.         bigRect.top += GetMBarHeight() * 2;
  2255.         bigRect.left += 4;
  2256.         bigRect.bottom -= 4;
  2257.         bigRect.right -= 65;
  2258.             
  2259.             
  2260.         SetPort((GrafPtr) GetWindowPort(pWindow));
  2261.         LocalToGlobal(&TopLeft(rect));
  2262.         LocalToGlobal(&BotRight(rect));
  2263.         
  2264.         if ( (thePreflight.wantHScroll) || (thePreflight.doZoom) )
  2265.             {
  2266.             // now that we auto stagger, we don't need this line
  2267.             //rect.left = bigRect.left;
  2268.             rect.right = bigRect.right;
  2269.             }
  2270.             
  2271.         if ( (thePreflight.wantVScroll) || (thePreflight.doZoom) )
  2272.             {
  2273.             // now that we auto stagger, we don't need this line
  2274.             //rect.top = bigRect.top;
  2275.             rect.bottom = bigRect.bottom;
  2276.             }
  2277.         
  2278.         // can't have an invalid rectangle
  2279.         if (rect.right - rect.left < 32)
  2280.             rect.right = rect.left + 32;
  2281.  
  2282.         MoveWindow(pWindow, rect.left, rect.top, false);
  2283.         SizeWindow(pWindow, rect.right - rect.left, rect.bottom - rect.top, false);
  2284.         }
  2285.         
  2286.         // fill in the default contents of the window
  2287.         pData->windowKind         = windowKind;
  2288.         pData->originalFileType    = fileType;
  2289.         pData->pMakeWindow         = (MakeWindowProc)thePreflight.makeProcPtr;
  2290.         pData->resRefNum        = -1;
  2291.         pData->dataRefNum        = -1;
  2292.                 GetWindowPortBounds(pWindow, &pData->contentRect);
  2293.         
  2294.         // make the scroll bars
  2295.         {
  2296.         Rect    controlRect;
  2297.         
  2298.         if (thePreflight.wantHScroll)
  2299.             {
  2300.             pData->contentRect.bottom -= kScrollBarSize;
  2301.             GetWindowPortBounds(pWindow, &controlRect);
  2302.             controlRect.top = controlRect.bottom - 16;
  2303.             if (thePreflight.wantVScroll)
  2304.                 controlRect.right -= kGrowScrollAdjust;
  2305.             OffsetRect(&controlRect, -1, 1);
  2306.             CreateScrollBarControl(pWindow, &controlRect, 0, 0, 0, 0, true, gHActionProc, &pData->hScroll );
  2307.             }
  2308.         if (thePreflight.wantVScroll)
  2309.             {
  2310.             pData->contentRect.right -= kScrollBarSize;
  2311.                         GetWindowPortBounds(pWindow, &controlRect);
  2312.             controlRect.left = controlRect.right - 16;
  2313.             if (thePreflight.wantVScroll)
  2314.                 controlRect.bottom -= kGrowScrollAdjust;
  2315.             OffsetRect(&controlRect, 1, -1);
  2316.             CreateScrollBarControl(pWindow, &controlRect, 0, 0, 0, 0, true, gVActionProc, &pData-> vScroll );
  2317.             }
  2318.         }
  2319.  
  2320.         // got a name?  Open the file        
  2321.         if (fileSpec)
  2322.             {
  2323.             anErr = FSpOpenDF(fileSpec, thePreflight.openKind, &pData->dataRefNum);
  2324.             if     ( 
  2325.                     ((anErr == afpAccessDenied) || (anErr == opWrErr) || (anErr == permErr) ) && 
  2326.                     (thePreflight.openKind != fsRdPerm)
  2327.                 )
  2328.                 {
  2329.                 thePreflight.openKind = fsRdPerm;
  2330.                 pData->isWritable = false;
  2331.                 anErr = FSpOpenDF(fileSpec, thePreflight.openKind, &pData->dataRefNum);
  2332.                 }
  2333.             else
  2334.                 pData->isWritable = true;
  2335.             nrequire(anErr, FailedToOpenFile);
  2336.  
  2337.             // okay not to find a resource fork, because some don't have them                
  2338.             pData->resRefNum = FSpOpenResFile(fileSpec, thePreflight.openKind);
  2339.             
  2340.             // save the file spec in case someone is interested
  2341.             pData->fileSpec = *fileSpec;
  2342.             
  2343.             // alias for background file synchronization
  2344.             anErr = NewAlias( NULL, fileSpec, &pData->fileAlias );
  2345.             nrequire(anErr, GoshNoAlias );
  2346.             
  2347.             //
  2348.             // Most windows are not modifiable in SimpleText - only text files can be modified by SimpleText    
  2349.             //
  2350.             if( gMachineInfo.haveProxyIcons )
  2351.             {
  2352.                 SetWindowModified( pWindow, false );
  2353.                 SetWindowProxyFSSpec( pWindow, fileSpec );
  2354.             }
  2355.  
  2356.             }
  2357.             
  2358.         if (pData->pMakeWindow)
  2359.             {
  2360.             Rect oldContent = pData->contentRect;
  2361. #ifdef __MWERKS__
  2362. #if __option(profile)
  2363.             ProfilerSetStatus(true);
  2364. #endif
  2365. #endif
  2366.             anErr = (*(pData->pMakeWindow)) (pWindow, pData);
  2367. #ifdef __MWERKS__
  2368. #if __option(profile)
  2369.             ProfilerDump("\pmakewindow.prof");
  2370.             ProfilerSetStatus(false);
  2371.             ProfilerClear();
  2372. #endif
  2373. #endif
  2374.             if (!EqualRect(&oldContent, &pData->contentRect))
  2375.                 {
  2376.                 SizeWindow(pWindow, 
  2377.                         pData->contentRect.right  + (pData->vScroll != 0) * kScrollBarSize,
  2378.                         pData->contentRect.bottom + (pData->hScroll != 0) * kScrollBarSize,
  2379.                         false);
  2380.                 }
  2381.             }
  2382.         nrequire(anErr, FailedMakeWindow);
  2383.  
  2384.         // got a name?  Use it as the window title
  2385.         if ( (fileSpec) && (!pData->openAsNew) )
  2386.             SetWTitle(pWindow, fileSpec->name);
  2387.         else
  2388.             {
  2389.             if ((gMachineInfo.documentCount == 1) && (pData->windowKind == kTextWindow))
  2390.                 {
  2391.                 Str255 tempString;
  2392.         
  2393.                 GetIndString(tempString, kMiscStrings, iFirstNewDocumentTitle);    // get the "untitled" string (no number)
  2394.                 SetWTitle(pWindow, tempString);
  2395.                 }
  2396.             else
  2397.                 {
  2398.                 Str255    tempString;
  2399.                 Str32    numString;
  2400.     
  2401.                 GetWTitle(pWindow, tempString);
  2402.                 NumToString(gMachineInfo.documentCount, numString);
  2403.                 (void) ZeroStringSub(tempString, numString);
  2404.                 SetWTitle(pWindow, tempString);
  2405.                 }
  2406.  
  2407.             if (pData->bumpUntitledCount)
  2408.                 gMachineInfo.documentCount++;    // bump count if appropriate for this kind of document
  2409.             }
  2410.  
  2411.         // Make sure the scroll bars are reasonable in size, and move if they must
  2412.         AdjustScrollBars(pWindow, true, true, nil);
  2413.         
  2414.         // Show the scrollbars
  2415.         if( pData->hScroll != NULL )
  2416.             ShowControl( pData->hScroll );
  2417.             
  2418.         if( pData->vScroll != NULL )
  2419.             ShowControl( pData->vScroll );
  2420.         
  2421.         // finally, if all goes well, we can see the window itself!
  2422.         ShowWindow(pWindow);
  2423.         }
  2424.  
  2425.     return noErr;
  2426.  
  2427. // EXCEPTION HANDLING
  2428.  
  2429. FailedMakeWindow:
  2430.     DisposeHandle( (Handle)pData->fileAlias );
  2431.     
  2432. GoshNoAlias:
  2433.     if (pData->resRefNum != -1)
  2434.         CloseResFile(pData->resRefNum);
  2435.     if (pData->dataRefNum != -1)
  2436.         FSClose(pData->dataRefNum);
  2437.         
  2438. FailedToOpenFile:
  2439.     DisposeWindow(pWindow);
  2440.     
  2441. NewWindowFailed:
  2442.     DisposePtr((Ptr)pData);
  2443.     
  2444. FailedToAllocateWindow:
  2445. PreflightFailed:
  2446. SanityCheckFailed:
  2447.     return anErr;
  2448.     
  2449. } // MakeNewWindow
  2450.  
  2451. // --------------------------------------------------------------------------------------------------------------
  2452. #pragma segment Main
  2453.  
  2454. #define dontSaveChanges 3
  2455.  
  2456. #define kVisualDelay 8
  2457.  
  2458. static pascal Boolean SaveChangesFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  2459. {
  2460.     if (StdFilterProc(theDialog, theEvent, itemHit))
  2461.         return true;
  2462.  
  2463.     if (theEvent->what == updateEvt)
  2464.         {
  2465.         HandleEvent(theEvent);
  2466.         }
  2467.  
  2468.     if (theEvent->what == keyDown)
  2469.         {
  2470.         StringPtr keyEquivs = *GetString(kSaveChangesWindowID);
  2471.         unsigned char theKey = theEvent->message & charCodeMask;
  2472.  
  2473.         if (keyEquivs && (theKey == keyEquivs[1] || theKey == keyEquivs[2]))
  2474.             {
  2475.             short itemType;
  2476.             Rect theRect;
  2477.             ControlRef theControl;
  2478.             UInt32 finalTicks;
  2479.  
  2480.             GetDialogItem(theDialog, dontSaveChanges, &itemType, (Handle *) &theControl, &theRect);
  2481.             HiliteControl(theControl, kControlButtonPart);
  2482.             Delay(kVisualDelay, &finalTicks);
  2483.             HiliteControl(theControl, 0);
  2484.  
  2485.             *itemHit = dontSaveChanges;
  2486.             return true;
  2487.             }
  2488.         }
  2489.  
  2490.     return false;
  2491. }
  2492.  
  2493.  
  2494. static OSErr DoCloseWindow(WindowPtr pWindow, Boolean quitting, long keyTime)
  2495. {
  2496.     OSErr            anErr = noErr;
  2497.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  2498.     
  2499.     if ( (pData) && (pData->changed) )
  2500.         {
  2501.         short         hit;
  2502.         Str255        wTitle;
  2503.         DialogPtr    dPtr;
  2504.         Cursor        arrow;
  2505.  
  2506.         GetWTitle(pWindow, wTitle);
  2507.         SetCursor(GetQDGlobalsArrow(&arrow));
  2508.         ParamText(wTitle, "\p", "\p", "\p");
  2509.         
  2510.         if (gMachineInfo.haveNavigationServices)
  2511.             {
  2512.             hit = ConfirmSaveDialog(wTitle, quitting, MyEventProc);
  2513.             }
  2514.         else
  2515.             {
  2516.             hit = cancel;
  2517.             dPtr = GetNewDialog(kSaveChangesWindowID, nil, (WindowPtr)-1);
  2518.             if (dPtr)
  2519.                 {
  2520.                 SetDialogDefaultItem(dPtr, ok);
  2521.                 SetDialogCancelItem (dPtr, cancel);
  2522.                 BeginMovableModal();
  2523.                 do
  2524.                     {
  2525.                     MovableModalDialog(SaveChangesFilter, &hit);
  2526.                     } while ((hit != dontSaveChanges) && (hit != ok) && (hit != cancel));
  2527.                     
  2528.                 DisposeDialog(dPtr);
  2529.                 EndMovableModal();
  2530.                 }
  2531.             }
  2532.         switch (hit)
  2533.             {
  2534.             case ok:
  2535.                 anErr = DoCommand(pWindow, cSave, 0, 0);
  2536.                 if (anErr == eUserCanceled)        // redundant?
  2537.                     gAllDone = false;
  2538.                 break;
  2539.                 
  2540.             case cancel:
  2541.                 anErr = eUserCanceled;
  2542.                 gAllDone = false;
  2543.                 break;
  2544.                 
  2545.             case dontSaveChanges:
  2546.                 // don't save, so just close it
  2547.                 break;
  2548.             }
  2549.         }
  2550.  
  2551.     if (anErr == noErr)
  2552.         {
  2553.         if ( (pData) && (pData->pCloseWindow) )
  2554.             {
  2555.             // let the object close the window if it wishes to
  2556.             anErr = (*(pData->pCloseWindow)) (pWindow, pData);
  2557.             }
  2558.  
  2559.         // otherwise we close it the default way
  2560.         if (anErr == noErr)
  2561.             {
  2562.             if (pData)
  2563.                 {
  2564.                 DisposeWindow(pWindow);
  2565.     
  2566.                 if (pData->hPageFormat)
  2567.                 {
  2568.                     DisposeHandle((Handle) pData->hPageFormat);
  2569.                     pData->hPageFormat = nil;
  2570.                 }
  2571.                 if (pData->hPrintSettings)
  2572.                 {
  2573.                     DisposeHandle((Handle) pData->hPrintSettings);
  2574.                     pData->hPrintSettings = nil;
  2575.                 }
  2576.                     
  2577.                 if (pData->resRefNum != -1)
  2578.                     CloseResFile(pData->resRefNum);
  2579.                 if (pData->dataRefNum != -1)
  2580.                     FSClose(pData->dataRefNum);
  2581.                 DisposePtr((Ptr) pData);
  2582.                 }
  2583.             }
  2584.         }
  2585.  
  2586.     // If we closed the last window, clean up
  2587.     if (FrontWindow() == nil)
  2588.         {
  2589.         UnhiliteMenuDelayed(keyTime);        // unhilite before adjusting menus to avoid ugly menu title flashing
  2590.         AdjustMenus(nil, true, false);
  2591.         gMachineInfo.documentCount = 1;        // back to "untitled"
  2592.         }
  2593.     
  2594.     // make sure we update the cursor
  2595.     SetEmptyRgn(gCursorRgn);
  2596.     
  2597.     return anErr;
  2598.     
  2599. } // DoCloseWindow
  2600.  
  2601. #undef dontSaveChanges
  2602.  
  2603. // --------------------------------------------------------------------------------------------------------------
  2604. #pragma segment Main
  2605.  
  2606. static OSErr    DetermineWindowTypeOrOpen(
  2607.     FSSpecPtr theSpec, OSType theType,                 // optional input params -- file to open
  2608.     OSType *returnedTypeList, short * pNumTypes,    // optional input params -- returns list of files
  2609.     Boolean *pWasAlreadyOpen)                        // optional input params -- was file already open
  2610. {
  2611.     OSErr        anErr = noErr;
  2612.     OSType        typeList[20];
  2613.     OSType        docList[20];
  2614.     short        numTypes;
  2615.  
  2616.     // use local copies if the input params are nil    
  2617.     if (returnedTypeList == nil)
  2618.         returnedTypeList = &typeList[0];
  2619.     if (pNumTypes == nil)
  2620.         pNumTypes = &numTypes;
  2621.     *pNumTypes = 0;
  2622.     
  2623.     // Load up all of the file types we know how to handle
  2624.     AboutGetFileTypes(returnedTypeList, docList, pNumTypes);
  2625.     PICTGetFileTypes(returnedTypeList, docList, pNumTypes);
  2626. #if ALLOW_QUICKTIME
  2627.     MovieGetFileTypes(returnedTypeList, docList, pNumTypes);
  2628. #endif
  2629.     ClipboardGetFileTypes(returnedTypeList, docList, pNumTypes);
  2630.     TextGetFileTypes(returnedTypeList, docList, pNumTypes);
  2631. #if ALLOW_QUICKTIME
  2632.     ThreeDGetFileTypes(returnedTypeList, docList, pNumTypes);
  2633. #endif
  2634.  
  2635.     if (theSpec != nil)
  2636.         {
  2637.         short         index;
  2638.         OSType        windowType = '????';
  2639.  
  2640.         for (index = 0; index < (*pNumTypes); ++index)
  2641.             if (theType == returnedTypeList[index])
  2642.                 windowType = docList[index];
  2643.         
  2644. #if ALLOW_QUICKTIME
  2645.         if (windowType == '????' && gMachineInfo.haveQuickTime)
  2646.             {
  2647.             ComponentDescription    ci;
  2648.             ci.componentType = GraphicsImporterComponentType;
  2649.             ci.componentSubType = theType;
  2650.             ci.componentManufacturer = kAnyComponentManufacturer;
  2651.             ci.componentFlags = 0;
  2652.             ci.componentFlagsMask = movieImportSubTypeIsFileExtension;
  2653.             if( 0 != FindNextComponent( 0, &ci ) )
  2654.             {
  2655.                 windowType = 'PICT';
  2656.             }
  2657.             }
  2658. #endif
  2659.         
  2660.         if (windowType != '????')
  2661.             {
  2662.             
  2663.             if ( (theType == 'TEXT') || (theType == 'sEXT') )
  2664.                 {
  2665.                 FInfo    theInfo;
  2666.                 
  2667.                 FSpGetFInfo(theSpec, &theInfo);
  2668.                 if ((theInfo.fdFlags & kIsStationery) != 0)
  2669.                     theType = 'sEXT';
  2670.                 else
  2671.                     theType = 'TEXT';
  2672.                 }
  2673.                 
  2674.             anErr = MakeNewWindow(windowType, theSpec, theType, pWasAlreadyOpen);
  2675.             }
  2676.         else
  2677.             anErr = eDocumentWrongKind;
  2678.         }
  2679.         
  2680.         
  2681.     return anErr;
  2682.     
  2683. } // DetermineWindowTypeOrOpen
  2684.  
  2685. // --------------------------------------------------------------------------------------------------------------
  2686. #pragma segment Main
  2687.  
  2688. #if 0
  2689. // Handle update/activate events behind Standard File
  2690. static pascal Boolean OpenDialogFilter(DialogPtr theDialog, EventRecord *theEvent,
  2691.                                       short *itemHit, void *myDataPtr)
  2692. {
  2693.     #pragma unused(myDataPtr)
  2694.  
  2695.     // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
  2696.     // drastically changing how the system handles the menu bar during our alert)
  2697.     if ( (theEvent->what == updateEvt) && (theEvent->message != (long)theDialog) )
  2698.         HandleEvent(theEvent);
  2699.  
  2700.     if (StdFilterProc(theDialog, theEvent, itemHit))
  2701.         return(true);
  2702.  
  2703.     return(false);
  2704.  
  2705. } // OpenDialogFilter
  2706. #endif
  2707.  
  2708. #if 0
  2709. #if GENERATINGCFM
  2710.     static RoutineDescriptor gOpenDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, OpenDialogFilter);
  2711.     static ModalFilterYDUPP gOpenDialogFilter = &gOpenDialogFilterRD;
  2712. #else
  2713.     static ModalFilterYDUPP gOpenDialogFilter = NewModalFilterYDProc(OpenDialogFilter);
  2714. #endif
  2715. #endif
  2716.  
  2717. static OSErr DoOpenWindow(void)
  2718. {
  2719.     OSErr                anErr = noErr;
  2720.     short                numTypes;
  2721.     OSType                typeList[20];
  2722. //    Point thePoint = { -1, -1 };
  2723.     FSSpec                fileSpec;
  2724.     OSType                fileType = '????';
  2725.     Boolean                fileSelected = false;
  2726.  
  2727.         DetermineWindowTypeOrOpen(nil, fileType, &typeList[0], &numTypes, nil);
  2728.     
  2729.     if (gMachineInfo.haveNavigationServices)
  2730.         {
  2731.         #if qSingleSelectionOnly
  2732.             fileSelected = OpenFileDialog('ttxt', numTypes, typeList, MyEventProc, &fileSpec, &fileType) == noErr;
  2733.         #else
  2734.             // Open as many documents as the user wishes thruogh Appleevents
  2735.             OpenFileDialog('ttxt', numTypes, typeList, MyEventProc, NULL, NULL);
  2736.             fileSelected = false;
  2737.         #endif
  2738.         }
  2739.     else 
  2740.         {
  2741. #if(0)
  2742.         StandardFileReply    sfReply;
  2743.         if (gMachineInfo.haveQuickTime)
  2744.             {
  2745.             CustomGetFilePreview(nil, numTypes, typeList, &sfReply, 0, thePoint, nil, gOpenDialogFilter, nil, nil, nil);
  2746.             }
  2747.         else
  2748.             {
  2749.             CustomGetFile(nil, numTypes, typeList, &sfReply, 0, thePoint, nil, gOpenDialogFilter, nil, nil, nil);
  2750.             }
  2751.         fileSelected= sfReply.sfGood;
  2752.         fileSpec    = sfReply.sfFile;
  2753.         fileType    = sfReply.sfType;
  2754. #endif
  2755.         }
  2756.     if (fileSelected)
  2757.         {
  2758.         Cursor arrow;
  2759.         SetWatchCursor();
  2760.         
  2761.         anErr = DetermineWindowTypeOrOpen(&fileSpec, fileType, &typeList[0], &numTypes, nil);
  2762.  
  2763.         SetCursor(GetQDGlobalsArrow(&arrow));
  2764.         }
  2765.         
  2766.     return anErr;
  2767.     
  2768. } // DoOpenWindow
  2769.  
  2770. // --------------------------------------------------------------------------------------------------------------
  2771. #pragma segment Main
  2772.  
  2773. static OSErr DoUpdateWindow(WindowPtr pWindow)
  2774. {
  2775.     OSErr            anErr = noErr;
  2776.     WindowDataPtr    pData = GetWindowInfo(pWindow);
  2777.     GrafPtr            curPort;
  2778.     
  2779.     // only handle updates for windows we know about
  2780.     if (pData)
  2781.         {
  2782.         GetPort(&curPort);
  2783.         SetPort((GrafPtr)GetWindowPort(pWindow));
  2784.         BeginUpdate(pWindow);
  2785.                     
  2786.         if (pData->pUpdateWindow)
  2787.             anErr = (*(pData->pUpdateWindow)) (pWindow, pData);
  2788.     
  2789.         EndUpdate(pWindow);
  2790.         SetPort(curPort);
  2791.         }
  2792.     
  2793.     return anErr;
  2794.     
  2795. } // DoUpdateWindow
  2796.  
  2797. // --------------------------------------------------------------------------------------------------------------
  2798. #pragma segment Main
  2799.  
  2800. OSErr DoScrollContent(WindowPtr pWindow, WindowDataPtr pData, short deltaH, short deltaV)
  2801. {
  2802.     OSErr    anErr = noErr;
  2803.     
  2804.     if ((deltaH) || (deltaV))
  2805.         {        
  2806.         if ((pData) && (pData->pScrollContent))
  2807.             anErr = (*(pData->pScrollContent)) (pWindow, pData, deltaH, deltaV);
  2808.             
  2809.         if (anErr == noErr)
  2810.             {
  2811.             RgnHandle    invalidRgn = NewRgn();
  2812.             
  2813.             ScrollRect(&pData->contentRect, deltaH, deltaV, invalidRgn);
  2814.             InvalWindowRgn(pWindow,invalidRgn);
  2815.             DisposeRgn(invalidRgn);
  2816.     
  2817.             DoUpdateWindow(pWindow);
  2818.             }
  2819.         }
  2820.     
  2821.     return anErr;
  2822.     
  2823. } // DoScrollContent
  2824.  
  2825.  
  2826. // --------------------------------------------------------------------------------------------------------------
  2827. #pragma segment Main
  2828.  
  2829. static OSErr DoContentClick(WindowPtr pWindow)
  2830. {
  2831.     OSErr            anErr = noErr;
  2832.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  2833.     
  2834.     
  2835.     if ( pData )
  2836.         {
  2837.         SetPort((GrafPtr) GetWindowPort(pWindow));
  2838.         
  2839.         if (pData->pContentClick)
  2840.             {
  2841.             // let the object handle the click if it wishes to
  2842.             anErr = (*(pData->pContentClick)) (pWindow, pData, &gEvent);
  2843.             
  2844.             // invalidate the cursor rgn in case the object changed its appearance
  2845.             if (anErr != noErr)
  2846.                 SetEmptyRgn(gCursorRgn);
  2847.             }
  2848.         
  2849.         if (anErr == noErr) 
  2850.             {
  2851.             ControlHandle    theControl;
  2852.             short            part;
  2853.             
  2854.             GlobalToLocal(&gEvent.where);
  2855.             part = FindControl(gEvent.where, pWindow, &theControl);
  2856.             switch (part)
  2857.                 {
  2858.                 // do nothing for viewRect case
  2859.                 case 0:
  2860.                     break;
  2861.  
  2862.                 // track the thumb, and then update all at once
  2863.                 case kControlIndicatorPart:
  2864.                     {
  2865.                     short    value = GetControlValue(theControl);
  2866.                     
  2867.                     if (gMachineInfo.haveAppearanceMgr)
  2868.                         {
  2869.                         if (theControl == pData->hScroll)
  2870.                             {
  2871.                             pData->oldHValue = GetControlValue(theControl);
  2872.                             part = TrackControl(theControl, gEvent.where, gHActionProc);
  2873.                             }
  2874.                         if (theControl == pData->vScroll)
  2875.                             {
  2876.                             pData->oldVValue = GetControlValue(theControl);
  2877.                             part = TrackControl(theControl, gEvent.where, gVActionProc);
  2878.                             }
  2879.                         }
  2880.                     else
  2881.                         {
  2882.                         part = TrackControl(theControl, gEvent.where, nil);
  2883.                         if (part != 0)
  2884.                             {
  2885.                             // turn the value into a delta
  2886.                             value -= GetControlValue(theControl);
  2887.                             
  2888.                             // if we actually moved
  2889.                             if (value != 0)
  2890.                                 {
  2891.                                 if (theControl == pData->hScroll)
  2892.                                     DoScrollContent(pWindow, pData, value, 0);
  2893.                                 if (theControl == pData->vScroll)
  2894.                                     DoScrollContent(pWindow, pData, 0, value);
  2895.                                     
  2896.                                 }
  2897.                             }
  2898.                         }
  2899.                     }
  2900.                     break;
  2901.                     
  2902.                 // track the control, and scroll as we go
  2903.                 default:
  2904.                     if (theControl)
  2905.                         {
  2906.                         if (theControl == pData->hScroll)
  2907.                             part = TrackControl(theControl, gEvent.where, gHActionProc);
  2908.                         if (theControl == pData->vScroll)
  2909.                             part = TrackControl(theControl, gEvent.where, gVActionProc);
  2910.                         }
  2911.                     break;
  2912.                 }
  2913.             }
  2914.  
  2915.         }
  2916.  
  2917.         
  2918.     return anErr;
  2919.     
  2920. } // DoContentClick
  2921.  
  2922. // --------------------------------------------------------------------------------------------------------------
  2923. #pragma segment Main
  2924. static OSErr DoGrowWindow(WindowPtr pWindow, EventRecord *pEvent)
  2925. {
  2926.     OSErr            anErr = noErr;
  2927.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  2928.     Rect            tempRect;
  2929.     LongRect        docRect;
  2930.     long            growResult;
  2931.     
  2932.     if (pData)
  2933.         {
  2934.         GrafPtr    pPort = (GrafPtr)GetWindowPort(pWindow);
  2935.         
  2936.         SetPort(pPort);
  2937.         
  2938.         RectToLongRect(&pData->contentRect, &docRect);
  2939.         if (pData->pGetDocumentRect)
  2940.             (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, true);
  2941.         if (pData->vScroll)
  2942.             docRect.right += 16;
  2943.         if (pData->hScroll)
  2944.             docRect.bottom += 16;
  2945.         
  2946.         if ( (pData->hasGrow) && (pData->hScroll == nil) && (pData->vScroll == nil) )
  2947.             {
  2948.             docRect.right += 16;
  2949.             docRect.bottom += 16;
  2950.             }
  2951.             
  2952.         // set up resize constraints
  2953.         tempRect.left = pData->minHSize;
  2954.         if (tempRect.left == 0)
  2955.             tempRect.left = kMinDocSize;
  2956.         tempRect.right = docRect.right - docRect.left;
  2957.         if (tempRect.right < tempRect.left)
  2958.             tempRect.right = tempRect.left;
  2959.         tempRect.top = pData->minVSize;
  2960.         if (tempRect.top == 0)
  2961.             tempRect.top = kMinDocSize;
  2962.         tempRect.bottom = docRect.bottom - docRect.top;
  2963.         if (tempRect.bottom < tempRect.top)
  2964.             tempRect.bottom = tempRect.top;
  2965.             
  2966.         growResult = GrowWindow(pWindow, pEvent->where, &tempRect);
  2967.         if ( growResult != 0 ) 
  2968.             {
  2969.             Rect        oldRect;
  2970.             Boolean        needInvalidate;
  2971.             
  2972.             // save old content area
  2973.             oldRect = pData->contentRect;
  2974.             
  2975.             // grow window and recalc what is needed
  2976.             SizeWindow(pWindow, growResult & 0xFFFF, growResult >> 16, true);
  2977.             GetWindowPortBounds(pWindow, &pData->contentRect);
  2978.             AdjustScrollBars(pWindow, true, true, &needInvalidate);
  2979.             
  2980.             if (needInvalidate)
  2981.                 {
  2982.                 InvalWindowRect(pWindow, &pData->contentRect);
  2983.                 }
  2984.  
  2985.             // if we have offset scrollbars, then force a redraw of them
  2986.             if (pData->hScrollOffset)
  2987.                 {
  2988.                 GetWindowPortBounds(pWindow, &oldRect);
  2989.                 oldRect.right = oldRect.left + pData->hScrollOffset;
  2990.                 oldRect.top = oldRect.bottom - kScrollBarSize;
  2991.                 InvalWindowRect(pWindow,&oldRect);
  2992.                 }
  2993.             if (pData->vScrollOffset)
  2994.                 {
  2995.                                 GetWindowPortBounds(pWindow, &oldRect);
  2996.                 oldRect.bottom = oldRect.top + pData->vScrollOffset;
  2997.                 oldRect.left = oldRect.right - kScrollBarSize;
  2998.                 InvalWindowRect(pWindow,&oldRect);
  2999.                 }
  3000.             }
  3001.             
  3002.         }
  3003.         
  3004.     
  3005.     return anErr;
  3006.     
  3007. } // DoGrowWindow
  3008.  
  3009. // --------------------------------------------------------------------------------------------------------------
  3010. #pragma segment Main
  3011.  
  3012. static OSErr DoZoomWindow(WindowPtr pWindow, short zoomDir)
  3013. {
  3014.     Rect                windRect, zoomRect;
  3015.     Rect                globalPortRect, theSect, dGDRect;
  3016.     GDHandle            nthDevice, dominantGDevice;
  3017.     long                sectArea, greatestArea;
  3018.     short                 hMax, vMax;
  3019.     Rect                bounds;
  3020.  
  3021.     // determine the max size of the window
  3022.     {
  3023.     WindowDataPtr            pData = GetWindowInfo(pWindow);
  3024.     LongRect            docRect;
  3025.     
  3026.     RectToLongRect(&pData->contentRect, &docRect);
  3027.     if (pData->pGetDocumentRect)
  3028.         (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, true);
  3029.     if (pData->vScroll)
  3030.         docRect.right += kScrollBarSize;
  3031.     if (pData->hScroll)
  3032.         docRect.bottom += kScrollBarSize;
  3033.     
  3034.     if ( (pData->hasGrow) && (pData->hScroll == nil) && (pData->vScroll == nil) )
  3035.         {
  3036.         docRect.right += kScrollBarSize;
  3037.         docRect.bottom += kScrollBarSize;
  3038.         }
  3039.  
  3040.     hMax = docRect.right - docRect.left;
  3041.     vMax = docRect.bottom - docRect.top;
  3042.     }
  3043.     
  3044.     SetPort((GrafPtr) GetWindowPort(pWindow));
  3045.         GetWindowPortBounds(pWindow, &bounds);
  3046.     EraseRect(&bounds);    // recommended for cosmetic reasons
  3047.  
  3048.     if (zoomDir == inZoomOut) 
  3049.         {
  3050.  
  3051.         /*
  3052.          *    ZoomWindow() is a good basic tool, but it doesn't do everything necessary to
  3053.          *    implement a good human interface when zooming. In fact it's not even close for
  3054.          *    more high-end hardware configurations. We must help it along by calculating an
  3055.          *    appropriate window size and location any time a window zooms out.
  3056.          */
  3057.         {
  3058.         RgnHandle    structRgn = NewRgn();
  3059.         
  3060.         GetWindowRegion(pWindow, kWindowStructureRgn, structRgn);
  3061.  
  3062.         GetRegionBounds( structRgn, &windRect);
  3063.  
  3064.         DisposeRgn(structRgn);
  3065.         }
  3066.         dominantGDevice = nil;
  3067.  
  3068.         /*
  3069.          *    Color QuickDraw implies the possibility of multiple monitors. This is where
  3070.          *    zooming becomes more interesting. One should zoom onto the monitor containing
  3071.          *    the greatest portion of the window. This requires walking the gDevice list.
  3072.          */
  3073.  
  3074.         nthDevice = GetDeviceList();
  3075.         greatestArea = 0;
  3076.         while (nthDevice != nil) 
  3077.             {
  3078.             if (TestDeviceAttribute(nthDevice, screenDevice)) 
  3079.                 {
  3080.                 if (TestDeviceAttribute(nthDevice, screenActive)) 
  3081.                     {
  3082.                     SectRect(&windRect, &(**nthDevice).gdRect, &theSect);
  3083.                     sectArea = (long) RectWidth(theSect) * (long) RectHeight(theSect);
  3084.                     if (sectArea > greatestArea) 
  3085.                         {
  3086.                         greatestArea = sectArea;        // save the greatest intersection
  3087.                         dominantGDevice = nthDevice;    // and which device it belongs to
  3088.                         }
  3089.                     }
  3090.                 }
  3091.             nthDevice = GetNextDevice(nthDevice);
  3092.             }
  3093.  
  3094.         /*
  3095.          *    At this point, we know the dimensions of the window we're zooming, and we know
  3096.          *    what screen we're going to put it on. To be more specific, however, we need a
  3097.          *    rectangle which defines the maximum dimensions of the resized window's contents.
  3098.          *    This rectangle accounts for the thickness of the window frame, the menu bar, and
  3099.          *    one or two pixels around the edges for cosmetic compatibility with ZoomWindow().
  3100.          */
  3101.  
  3102.         if (dominantGDevice != nil) 
  3103.             {
  3104.             dGDRect = (**dominantGDevice).gdRect;
  3105.             if (dominantGDevice == GetMainDevice())        // account for menu bar on main device
  3106.                 dGDRect.top += GetMBarHeight();
  3107.             }
  3108.         else 
  3109.             {
  3110.             BitMap bitmap;
  3111.                         GetQDGlobalsScreenBits(&bitmap);
  3112.                         dGDRect = bitmap.bounds
  3113. ;    // if no gDevice, use default monitor
  3114.             dGDRect.top += GetMBarHeight();
  3115.             }
  3116.  
  3117.         GetWindowPortBounds(pWindow, &globalPortRect);
  3118.         LocalToGlobal(&TopLeft(globalPortRect));        // calculate the window's portRect
  3119.         LocalToGlobal(&BotRight(globalPortRect));        // in global coordinates
  3120.  
  3121.         // account for the window frame and inset it a few pixels
  3122.         dGDRect.left    += 2 + globalPortRect.left - windRect.left;
  3123.         dGDRect.top        += 2 + globalPortRect.top - windRect.top;
  3124.         dGDRect.right    -= 1 + windRect.right - globalPortRect.right;
  3125.         dGDRect.bottom    -= 1 + windRect.bottom - globalPortRect.bottom;
  3126.  
  3127.         /*
  3128.          *    Now we know exactly what our limits are, and since there are input parameters
  3129.          *    specifying the dimensions we'd like to see, we can move and resize the zoom
  3130.          *    state rectangle for the best possible results. We have three goals in this:
  3131.          *    1. Display the window entirely visible on a single device.
  3132.          *    2. Resize the window to best represent the dimensions of the document itself.
  3133.          *    3. Move the window as short a distance as possible to achieve #1 and #2.
  3134.          */
  3135.  
  3136.         //zoomRect = &(**(WStateDataHandle) ((WindowPeek) pWindow)->dataHandle).stdState;
  3137.                 GetWindowIdealUserState(pWindow, &zoomRect);                
  3138.         /*
  3139.          *    Initially set the zoom rectangle to the size requested by the input parameters,
  3140.          *    although not smaller than a minimum size. We do this without moving the origin.
  3141.          */
  3142.  
  3143.         zoomRect.right = (zoomRect.left = globalPortRect.left) +
  3144.                                 Max(hMax, kMinDocSize);
  3145.         zoomRect.bottom = (zoomRect.top = globalPortRect.top) +
  3146.                                 Max(vMax, kMinDocSize);
  3147.  
  3148.         // Shift the entire rectangle if necessary to bring its origin inside dGDRect.
  3149.         OffsetRect(&zoomRect,
  3150.                     Max(dGDRect.left - zoomRect.left, 0),
  3151.                     Max(dGDRect.top - zoomRect.top, 0));
  3152.  
  3153.         /*
  3154.          *    Shift the rectangle up and/or to the left if necessary to accomodate the view,
  3155.          *    and if it is possible to do so. The rectangle may not be moved such that its
  3156.          *    origin would fall outside of dGDRect.
  3157.          */
  3158.  
  3159.         OffsetRect(&zoomRect,
  3160.                     -Pin(zoomRect.right - dGDRect.right, 0, zoomRect.left - dGDRect.left),
  3161.                     -Pin(zoomRect.bottom - dGDRect.bottom, 0, zoomRect.top - dGDRect.top));
  3162.  
  3163.         // Clip expansion to dGDRect, in case view is larger than dGDRect.
  3164.         zoomRect.right = Min(zoomRect.right, dGDRect.right);
  3165.         zoomRect.bottom = Min(zoomRect.bottom, dGDRect.bottom);
  3166.  
  3167.                 SetWindowIdealUserState(pWindow, &zoomRect);
  3168.         }
  3169.  
  3170.     ZoomWindow(pWindow, zoomDir, pWindow == FrontWindow());
  3171.     
  3172.     AdjustScrollBars(pWindow, true, true, nil);
  3173.  
  3174.     GetWindowPortBounds(pWindow, &bounds);
  3175.     InvalWindowRect(pWindow,&bounds);
  3176.     
  3177.     return noErr;
  3178.     
  3179. } // DoZoomWindow
  3180.  
  3181. // --------------------------------------------------------------------------------------------------------------
  3182. #pragma segment Main
  3183.  
  3184. OSErr DoActivate(WindowPtr pWindow, Boolean activating)
  3185. {
  3186.  
  3187.     OSErr            anErr = noErr;
  3188.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  3189.     
  3190.     SetPort((GrafPtr) GetWindowPort(pWindow));
  3191.     
  3192.     if ( pData )
  3193.         {
  3194.         if (pData->pActivateEvent)
  3195.             anErr = (*(pData->pActivateEvent)) (pWindow, pData, activating);
  3196.             
  3197.         if (anErr == noErr)
  3198.             {
  3199.             if (activating)
  3200.                 {
  3201.                 if (pData->hScroll)
  3202.                     HiliteControl( pData->hScroll, 0 );
  3203.                 if (pData->vScroll)
  3204.                     HiliteControl( pData->vScroll, 0 );
  3205.                 }
  3206.             else
  3207.                 {
  3208.                 if (pData->hScroll)
  3209.                     HiliteControl( pData->hScroll, kControlDisabledPart );
  3210.                 if (pData->vScroll)
  3211.                     HiliteControl( pData->vScroll, kControlDisabledPart );
  3212.                 }
  3213.             
  3214.             
  3215.             if ( pData->hasGrow )
  3216.                 {
  3217.                 Rect    growIconRect;
  3218.                 
  3219.                 CalculateGrowIcon(pWindow,pData, &growIconRect);
  3220.                 InvalWindowRect(pWindow,&growIconRect);
  3221.                 }
  3222.             }
  3223.         }
  3224.  
  3225.     AdjustMenus(pWindow, true, false);
  3226.         
  3227.     return anErr;
  3228.     
  3229. } // DoActivate
  3230.  
  3231. // --------------------------------------------------------------------------------------------------------------
  3232. #pragma segment Main
  3233. // --------------------------------------------------------------------------------------------------------------
  3234. #pragma segment Main
  3235.  
  3236. OSErr DoDefault(WindowDataPtr pData) {
  3237.     OSErr anErr = noErr;
  3238.  
  3239.     OSStatus status;
  3240.  
  3241.     status = PMBegin();
  3242.     
  3243.     // create default page format
  3244.     if ((status == noErr) && (pData->hPageFormat == nil))
  3245.     {
  3246.         PMPageFormat pageFormat = kPMNoPageFormat;
  3247.  
  3248.         status = PMNewPageFormat(&pageFormat);
  3249.         if ((status == noErr) && (pageFormat != kPMNoPageFormat))
  3250.             status = PMDefaultPageFormat(pageFormat);
  3251.  
  3252.         if (status == noErr)
  3253.             status = PMFlattenPageFormat(pageFormat, &pData->hPageFormat);
  3254.  
  3255.         if (pageFormat != kPMNoPageFormat)
  3256.             (void)PMDisposePageFormat(pageFormat);
  3257.     }
  3258.  
  3259.     // create default print settings
  3260.     if ((status == noErr) && (pData->hPrintSettings == nil))
  3261.     {
  3262.         PMPrintSettings printSettings = kPMNoPrintSettings;
  3263.  
  3264.         status = PMNewPrintSettings(&printSettings);
  3265.         if ((status == noErr) && (printSettings != kPMNoPrintSettings))
  3266.             status = PMDefaultPrintSettings(printSettings);
  3267.  
  3268.         if (status == noErr)
  3269.             status = PMFlattenPrintSettings(printSettings, &pData->hPrintSettings);
  3270.  
  3271.         if (printSettings != kPMNoPrintSettings)
  3272.             (void)PMDisposePrintSettings(printSettings);
  3273.  
  3274.     }
  3275.     (void)PMEnd();
  3276.  
  3277.     anErr = (OSErr)status;
  3278.     
  3279.     return anErr;
  3280. }
  3281.  
  3282. // --------------------------------------------------------------------------------------------------------------
  3283. #pragma segment Printing
  3284.  
  3285. OSErr    DoPageSetup(WindowPtr pWindow)
  3286. {
  3287.     OSErr            anErr = noErr;
  3288.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  3289.     Boolean         accepted;
  3290.         
  3291.     anErr = DoDefault(pData);
  3292.     nrequire(anErr, DoDefault);
  3293.     
  3294.     if (pData->hPageFormat != nil)
  3295.     {
  3296.         OSStatus status;
  3297.  
  3298.         status = PMBegin();
  3299.         if (status == noErr)
  3300.         {
  3301.             PMPageFormat pageFormat = kPMNoPageFormat;
  3302.  
  3303.             // retrieve the default page format
  3304.             status = PMUnFlattenPageFormat(pData->hPageFormat, &pageFormat);
  3305.  
  3306.             if ((status == noErr) && (pageFormat != kPMNoPageFormat))
  3307.             {
  3308.                 Cursor arrow;
  3309.  
  3310.                 SetCursor(GetQDGlobalsArrow(&arrow));
  3311.                 status = PMPageSetUpDialog(pageFormat, &accepted);
  3312.                 if (!accepted)
  3313.                     status = kPMCancel;
  3314.             }
  3315.  
  3316.             // save any changes to the page format
  3317.             if (status == noErr && accepted) {
  3318.                 DisposeHandle( pData->hPageFormat );
  3319.                 pData->hPageFormat = nil;
  3320.                 status = PMFlattenPageFormat(pageFormat, &pData->hPageFormat);
  3321.  
  3322.             }
  3323.             if (pageFormat != kPMNoPageFormat)
  3324.                 (void)PMDisposePageFormat(pageFormat);
  3325.         }
  3326.         (void)PMEnd();
  3327.  
  3328.         anErr = (OSErr)status;
  3329.     }
  3330.  
  3331. // FALL THROUGH EXCEPTION HANDLING
  3332. DoDefault:        
  3333.     return anErr;
  3334.     
  3335. } // DoPageSetup
  3336.  
  3337. // --------------------------------------------------------------------------------------------------------------
  3338. #pragma segment Printing
  3339.  
  3340. static OSErr    DoPrintSetup(WindowPtr pWindow, StringPtr pPrinterName)
  3341. {
  3342. #pragma unused (pPrinterName)
  3343.  
  3344.     OSErr            anErr = noErr;
  3345.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  3346.     Boolean         accepted;
  3347.         
  3348.     anErr = DoDefault(pData);
  3349.     nrequire(anErr, DoDefault);
  3350.     
  3351.     if ((pData->hPrintSettings != nil) && (pData->hPageFormat != nil))
  3352.     {
  3353.         OSStatus status;
  3354.  
  3355.         status = PMBegin();
  3356.         if (status == noErr)
  3357.         {
  3358.             PMPrintSettings printSettings = kPMNoPrintSettings;
  3359.             PMPageFormat pageFormat = kPMNoPageFormat;
  3360.  
  3361.             // retrieve the default printing objects
  3362.             status = PMUnFlattenPageFormat(pData->hPageFormat, &pageFormat);
  3363.             if (status == noErr)
  3364.                 status = PMUnFlattenPrintSettings(pData->hPrintSettings, &printSettings);
  3365.  
  3366.             if ((status == noErr) && (printSettings != kPMNoPrintSettings) && (pageFormat != kPMNoPageFormat))
  3367.             {
  3368.                 Cursor arrow;
  3369.                 SetCursor(GetQDGlobalsArrow(&arrow));
  3370.  
  3371.                 status = PMPrintDialog(printSettings, pageFormat, &accepted );
  3372.                 if (!accepted)
  3373.                     status = eUserCanceled;
  3374.             }
  3375.  
  3376.             if (status == noErr && accepted)
  3377.             {
  3378.                 // replace with the new print settings handle
  3379.                 // NOTE:  the pageFormat object does not get modified
  3380.                 DisposeHandle(pData->hPrintSettings);
  3381.                 pData->hPrintSettings = nil;
  3382.                 status = PMFlattenPrintSettings(printSettings, &pData->hPrintSettings);
  3383.             }
  3384.  
  3385.             if (printSettings != kPMNoPrintSettings)
  3386.                 (void)PMDisposePrintSettings(printSettings);
  3387.         }
  3388.         (void)PMEnd();
  3389.  
  3390.         anErr = (OSErr)status;
  3391.     }
  3392.         
  3393. // FALL THROUGH EXCEPTION HANDLING
  3394. DoDefault:        
  3395.     return anErr;
  3396.     
  3397. } // DoPrintSetup
  3398.  
  3399. // --------------------------------------------------------------------------------------------------------------
  3400. #pragma segment Printing
  3401.  
  3402. static OSErr    DoPrint(WindowPtr pWindow, void * hPageFormat, void * hPrintSettings, Boolean oneCopy)
  3403. {
  3404.     WindowDataPtr         pData = GetWindowInfo(pWindow);
  3405.     Boolean            didAllocate = false;
  3406.  
  3407.         OSStatus status;
  3408.         PMPageFormat pageFormat = kPMNoPageFormat;
  3409.         PMPrintSettings printSettings = kPMNoPrintSettings;
  3410.         PMPrintContext thePrintingPort = kPMNoReference;
  3411.         
  3412.         status = PMBegin();
  3413.         if (status == noErr)
  3414.         {
  3415.             if (hPageFormat != nil)
  3416.             {
  3417.                 status = PMUnFlattenPageFormat(hPageFormat, &pageFormat);
  3418.             }
  3419.             else
  3420.             {
  3421.                 status = PMNewPageFormat(&pageFormat);
  3422.                 if ((status == noErr) && (pageFormat != kPMNoPageFormat))
  3423.                     status = PMDefaultPageFormat(pageFormat);
  3424.             }
  3425.             if (hPrintSettings != nil)
  3426.             {
  3427.                 status = PMUnFlattenPrintSettings(hPrintSettings, &printSettings);
  3428.             }
  3429.             else
  3430.             {
  3431.                 status = PMNewPrintSettings(&printSettings);
  3432.                 if ((status == noErr) && (printSettings != kPMNoPrintSettings))
  3433.                     status = PMDefaultPrintSettings(printSettings);
  3434.             }
  3435.         }
  3436.  
  3437.         if (status == noErr)
  3438.         {
  3439.             long    pageIndex;
  3440.             UInt32    firstPage, lastPage;
  3441.             
  3442.             // be sure to get the page range BEFORE calling PrValidate(), 
  3443.             // which blows it away for many drivers.
  3444.             status = PMGetFirstPage(printSettings, &firstPage);
  3445.             if (status == noErr)
  3446.                 status = PMGetLastPage(printSettings, &lastPage);
  3447.  
  3448.             if (status == noErr)
  3449.                 status = PMValidatePrintSettings(printSettings, kPMDontWantBoolean);
  3450.  
  3451.              status = PMGetFirstPage(printSettings, &firstPage);
  3452.             if (status == noErr)
  3453.                 status = PMGetLastPage(printSettings, &lastPage);
  3454.  
  3455.            if (status == noErr)
  3456.                 status = PMSetFirstPage(printSettings, 1, true);
  3457.             if (status == noErr)
  3458.                 status = PMSetLastPage(printSettings, 9999, true);
  3459.  
  3460.            if ((status == noErr) && (oneCopy))
  3461.                 status = PMSetCopies(printSettings, 1, true);
  3462.  
  3463.             if (status == noErr)
  3464.             {
  3465.                 Rect    pageRect;
  3466.                 
  3467.                 status = PMBeginDocument(printSettings, pageFormat, &thePrintingPort);
  3468.                 if ((status == noErr) && (thePrintingPort != kPMNoReference))
  3469.                 {
  3470.                     PMRect  tempPageRect;
  3471.                     status = PMGetAdjustedPageRect(pageFormat, &tempPageRect);
  3472.                     if (status == noErr)
  3473.                     {
  3474.                         pageRect.top = tempPageRect.top;
  3475.                         pageRect.left = tempPageRect.left;
  3476.                         pageRect.bottom = tempPageRect.bottom;
  3477.                         pageRect.right = tempPageRect.right;
  3478.  
  3479.                 if (firstPage < 1)
  3480.                     firstPage = 1;
  3481.                 if (lastPage < firstPage)
  3482.                     lastPage = firstPage;
  3483.                 for (pageIndex = firstPage; pageIndex <= lastPage; ++pageIndex)
  3484.                     {
  3485.                             status = PMBeginPage(thePrintingPort, nil);
  3486.                             if (status == noErr)
  3487.                                 status = (OSStatus)(*(pData->pPrintPage)) (pWindow, pData, &pageRect, &pageIndex);
  3488.  
  3489.                             status = PMEndPage(thePrintingPort);
  3490.                             if ((status != noErr) || (pageIndex == -1))
  3491.                                 break;
  3492.                         }
  3493.                     }
  3494.  
  3495.                     (void)PMEndDocument(thePrintingPort);
  3496.                 }
  3497.             }
  3498.         }
  3499.  
  3500.         if (printSettings != kPMNoPrintSettings)
  3501.             (void)PMDisposePrintSettings(printSettings);
  3502.         if (pageFormat != kPMNoPageFormat)
  3503.             (void)PMDisposePageFormat(pageFormat);
  3504.         
  3505.         (void)PMEnd();
  3506.  
  3507.         return (OSErr)status;
  3508.     
  3509. } // DoPrint
  3510.  
  3511. // --------------------------------------------------------------------------------------------------------------
  3512. #pragma segment Main
  3513.  
  3514. OSErr    DoCommand(WindowPtr pWindow, short commandID, long menuResult, long keyTime)
  3515. {
  3516.     OSErr            anErr = noErr;
  3517.     WindowDataPtr     pData = nil;
  3518.     
  3519.     if (pWindow)
  3520.         {
  3521.         pData = (WindowDataPtr) GetWindowInfo(pWindow);
  3522.         
  3523.         if ( (pData) && (pData->pCommand) )
  3524.             anErr = (*(pData->pCommand)) (pWindow, pData, commandID, menuResult);
  3525.         }
  3526.     
  3527.     if (anErr == noErr)
  3528.         {
  3529.         // default command handling
  3530.         switch (commandID)
  3531.             {
  3532.             // About box command
  3533.             case cAbout:
  3534.                 if (!BringToFrontIfExists(kAboutWindow))
  3535.                     anErr = MakeNewWindow(kAboutWindow, nil, '????', nil);
  3536.                 break;
  3537. #if(0)                
  3538.             case cDeskAccessory:
  3539.                 {
  3540.                 Str255    tempString;
  3541.                 
  3542.                 GetMenuItemText(GetMenuHandle(menuResult>>16), menuResult & 0xFFFF, tempString);
  3543.                 OpenDeskAcc(tempString);
  3544.                 }
  3545.                 break;
  3546. #endif                
  3547.             // New window command
  3548.             case cNew:
  3549.                 anErr = MakeNewWindow(kTextWindow, nil, 'TEXT', nil);
  3550.                 break;
  3551.                 
  3552.             // Open window command
  3553.             case cOpen:
  3554.                 anErr = DoOpenWindow();
  3555.                 break;
  3556.                 
  3557.             // Close window command
  3558.             case cClose:
  3559.                 anErr = DoCloseWindow(pWindow, false, keyTime);
  3560.                 break;
  3561.                 
  3562.             case cPageSetup:
  3563.                 anErr = DoPageSetup(pWindow);
  3564.                 break;
  3565.                 
  3566.             case cPrint:
  3567.                 anErr = DoPrintSetup(pWindow, nil);
  3568.                 if (anErr == noErr)
  3569.                     anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, false);
  3570.                 break;
  3571.                 
  3572.             case cPrintOneCopy:
  3573.                 anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, true);
  3574.                 break;
  3575.                 
  3576.             // get out of here command!
  3577.             case cQuit:
  3578.                 gAllDone = true;
  3579.                 break;
  3580.     
  3581.             // show/hide clipboard
  3582.             case cShowClipboard:
  3583.                 if (!BringToFrontIfExists(kClipboardWindow))
  3584.                     {
  3585.                     anErr = MakeNewWindow(kClipboardWindow, nil, '????', nil);
  3586.                     }
  3587.                 else
  3588.                     {
  3589.                     pWindow = FrontWindow();
  3590.                     anErr = DoCloseWindow(pWindow, false, keyTime);
  3591.                     }
  3592.                 break;
  3593.                 
  3594.             case cNextPage:
  3595.                 gEvent.what = keyDown;
  3596.                 gEvent.message = kPageDown << 8;
  3597.                 gEvent.modifiers = 0;
  3598.                 DoKeyEvent(pWindow, &gEvent, false);
  3599.                 break;
  3600.                 
  3601.             case cPreviousPage:
  3602.                 gEvent.what = keyDown;
  3603.                 gEvent.message = kPageUp << 8;
  3604.                 gEvent.modifiers = 0;
  3605.                 DoKeyEvent(pWindow, &gEvent, false);
  3606.                 break;
  3607.                 
  3608.             // Do nothing command
  3609.             case cNull:
  3610.                 break;
  3611.                             
  3612.             default:
  3613.                 break;
  3614.             }
  3615.         }
  3616.         
  3617.     // don't report cancels
  3618.     if (anErr == kPMCancel)
  3619.         anErr = noErr;
  3620.     
  3621.     if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) && (anErr != eUserCanceled) )
  3622.         {
  3623.         // some commands are so similar to other commands that we map their IDs
  3624.         // for the purposes of the error strings
  3625.         if (commandID == cSaveAs)
  3626.             commandID = cSave;
  3627.         if (commandID == cPrintOneCopy)
  3628.             commandID = cPrint;
  3629.             
  3630.         ConductErrorDialog(anErr, commandID, cancel);
  3631.         }
  3632.         
  3633.     // in any case, unhilite the menu selected after command processing is done,
  3634.     // but first delay for a short while if the command was invoked via a cmd key
  3635.     // so that the menu title is hilighted long enough for the user to see it
  3636.     UnhiliteMenuDelayed(keyTime);
  3637.     
  3638.     return anErr;
  3639.     
  3640. } // DoCommand
  3641.  
  3642. // --------------------------------------------------------------------------------------------------------------
  3643. #pragma segment Main
  3644.  
  3645. static OSErr    DoMenuCommand(WindowPtr pWindow, long menuResult, long keyTime)
  3646. {
  3647.     OSErr    anErr = noErr;
  3648.     short    commandID = cNull;
  3649.     short    ** commandHandle;
  3650.     short    menuID = menuResult >> 16;
  3651.  
  3652.     if (menuID >= mFontSubMenusStart)
  3653.         {
  3654.         commandID = cSelectFontStyle;
  3655.         }
  3656.     else
  3657.         {
  3658.         // read in the resource that controls this menu
  3659.             {
  3660.             short    oldResFile = CurResFile();
  3661.             
  3662.             UseResFile(gApplicationResFile);
  3663.             commandHandle = (short**) Get1Resource('MCMD', menuID);
  3664.             UseResFile(oldResFile);
  3665.             anErr = ResError();
  3666.             nrequire(anErr, FailedToLoadCommandTable);
  3667.             }
  3668.         
  3669.         if (commandHandle)
  3670.             {
  3671.             short    item = menuResult & 0xFFFF;
  3672.             short    * pCommands = *commandHandle;
  3673.             
  3674.             if (item <= pCommands[0])
  3675.                 commandID = pCommands[item];
  3676.             else
  3677.                 commandID = pCommands[pCommands[0]];
  3678.             }
  3679.         }
  3680.     
  3681.     anErr = DoCommand(pWindow, commandID, menuResult, keyTime);
  3682.     
  3683. // FALL THROUGH EXCEPTION HANDLING
  3684. FailedToLoadCommandTable:
  3685.  
  3686.     return anErr;
  3687.     
  3688. } // DoMenuCommand
  3689.  
  3690.  
  3691. // --------------------------------------------------------------------------------------------------------------
  3692. #pragma segment Main
  3693.  
  3694. static void DoKeyPageDown(WindowPtr pWindow, WindowDataPtr pData, Boolean processPageControls)
  3695. {
  3696.  
  3697.     if (GetControlValue(pData->vScroll) < GetControlMaximum(pData->vScroll))
  3698.         VActionProc(pData->vScroll, kControlPageDownPart);
  3699.     else
  3700.         {
  3701.         if ( (processPageControls) && (IsCommandEnabled(cNextPage)) )
  3702.             {
  3703.             short amount;
  3704.  
  3705.             if (DoCommand(pWindow, cNextPage, 0, 0) == eActionAlreadyHandled)
  3706.                 {
  3707.                 amount = GetControlValue(pData->vScroll);
  3708.                 SetControlAndClipAmount(pData->vScroll, &amount);
  3709.                 if (amount != 0)
  3710.                     DoScrollContent(pWindow, pData, 0, amount);
  3711.                 }
  3712.             
  3713.             AdjustMenus(pWindow, true, false);
  3714.             }
  3715.         }
  3716.     
  3717. } // DoKeyPageDown
  3718.  
  3719. // --------------------------------------------------------------------------------------------------------------
  3720. #pragma segment Main
  3721.  
  3722. static void DoKeyPageUp(WindowPtr pWindow, WindowDataPtr pData, Boolean processPageControls)
  3723. {
  3724.     if (GetControlValue(pData->vScroll) > GetControlMinimum(pData->vScroll))
  3725.         VActionProc(pData->vScroll, kControlPageUpPart);
  3726.     else
  3727.         {
  3728.         if ( (processPageControls) && (IsCommandEnabled(cPreviousPage)) )
  3729.             {
  3730.             short amount;
  3731.             
  3732.             if (DoCommand(pWindow, cPreviousPage, 0, 0) == eActionAlreadyHandled)
  3733.                 {
  3734.                 amount = -(GetControlMaximum(pData->vScroll)-GetControlValue(pData->vScroll));
  3735.                 SetControlAndClipAmount(pData->vScroll, &amount);
  3736.                 if (amount != 0)
  3737.                     DoScrollContent(pWindow, pData, 0, amount);
  3738.                 }
  3739.             
  3740.             AdjustMenus(pWindow, true, false);
  3741.             }
  3742.         }
  3743.         
  3744. } // DoKeyPageUp
  3745.  
  3746. // --------------------------------------------------------------------------------------------------------------
  3747. #pragma segment Main
  3748.  
  3749. OSErr    DoKeyEvent(WindowPtr pWindow, EventRecord * pEvent, Boolean processPageControls)
  3750. {
  3751.     OSErr            anErr = noErr;
  3752.     WindowDataPtr     pData = nil;
  3753.     Boolean            passToObject = false;
  3754.     Boolean         isMotionKey = false;
  3755.     long            menuResult = 0;
  3756.     
  3757.     char keyCode = (pEvent->message >> 8) & charCodeMask;
  3758.  
  3759.     if (pWindow)
  3760.         pData = GetWindowInfo(pWindow);
  3761.     
  3762.     if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3763.         {
  3764.         if ( (pData) && (pData->pPreMenuAccess) )
  3765.             (void) (*(pData->pPreMenuAccess)) (pWindow, pData);
  3766.         AdjustMenus(pWindow, true, false);
  3767.         menuResult = MenuKey(pEvent->message & charCodeMask);
  3768.         DoMenuCommand(pWindow, menuResult, TickCount());
  3769.         pWindow = FrontWindow();
  3770.         }
  3771.  
  3772.     if (menuResult == 0)
  3773.         {
  3774.         if (pWindow)
  3775.             {
  3776.             if ( (pData) && (pData->pKeyEvent) )
  3777.                 passToObject = true;
  3778.             SetPort((GrafPtr) GetWindowPort(pWindow));
  3779.             }
  3780.             
  3781.         if (pData)
  3782.             {
  3783.             switch (keyCode)
  3784.                 {
  3785.                 case kHome: // top of file
  3786.                     isMotionKey = true;
  3787.                     if (pData->vScroll)
  3788.                         {
  3789.                         short amount;
  3790.                         
  3791.                         if ( (processPageControls) && (IsCommandEnabled(cGotoPage)) )
  3792.                             DoCommand(pWindow, cGotoPage, cGotoFirst, 0);
  3793.  
  3794.                         amount = GetControlValue(pData->vScroll);
  3795.                         SetControlAndClipAmount(pData->vScroll, &amount);
  3796.                         if (amount != 0)
  3797.                             DoScrollContent(pWindow, pData, 0, amount);
  3798.                         passToObject = false;
  3799.                         }
  3800.                     break;
  3801.                     
  3802.                 case kEnd: // end of file
  3803.                     isMotionKey = true;
  3804.                     if (pData->vScroll)
  3805.                         {
  3806.                         short amount;
  3807.  
  3808.                         if ( (processPageControls) && (IsCommandEnabled(cGotoPage)) )
  3809.                             DoCommand(pWindow, cGotoPage, cGotoLast, 0);
  3810.                             
  3811.                         amount = -(GetControlMaximum(pData->vScroll)-GetControlValue(pData->vScroll));
  3812.                         SetControlAndClipAmount(pData->vScroll, &amount);
  3813.                         if (amount != 0)
  3814.                             DoScrollContent(pWindow, pData, 0, amount);
  3815.                         passToObject = false;
  3816.                         }
  3817.                     break;
  3818.                     
  3819.                 case kPageUp: // scroll bar page up
  3820.                     isMotionKey = true;
  3821.                     if (pData->vScroll)
  3822.                         {
  3823.                         DoKeyPageUp(pWindow, pData, processPageControls);
  3824.                         passToObject = false;
  3825.                         }
  3826.                     break;
  3827.                     
  3828.                 case kPageDown: // scroll bar page down
  3829.                     isMotionKey = true;
  3830.                     if (pData->vScroll)
  3831.                         {
  3832.                         DoKeyPageDown(pWindow, pData, processPageControls);
  3833.                         passToObject = false;
  3834.                         }
  3835.                     break;
  3836.                             
  3837.                 case kUpArrow:        // scroll bar up arrow
  3838.                     isMotionKey = true;
  3839.                     if ( (pData->vScroll) && (!pData->pKeyEvent) )
  3840.                         {
  3841.                         if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3842.                             DoKeyPageUp(pWindow, pData, processPageControls);
  3843.                         else
  3844.                             VActionProc(pData->vScroll, kControlUpButtonPart);
  3845.                         passToObject = false;
  3846.                         }
  3847.                     break;
  3848.                     
  3849.                 case kDownArrow:    // scroll bar down arrow
  3850.                     isMotionKey = true;
  3851.                     if ( (pData->vScroll) && (!pData->pKeyEvent) )
  3852.                         {
  3853.                         if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3854.                             DoKeyPageDown(pWindow, pData, processPageControls);
  3855.                         else
  3856.                             VActionProc(pData->vScroll, kControlDownButtonPart);
  3857.                         passToObject = false;
  3858.                         }
  3859.                     break;
  3860.         
  3861.                 case kLeftArrow:    // scroll bar left arrow
  3862.                     isMotionKey = true;
  3863.                     if ( (pData->hScroll) && (!pData->pKeyEvent) )
  3864.                         {
  3865.                         if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3866.                             HActionProc(pData->hScroll, kControlPageUpPart);
  3867.                         else
  3868.                             HActionProc(pData->hScroll, kControlUpButtonPart);
  3869.                         passToObject = false;
  3870.                         }
  3871.                     break;
  3872.                     
  3873.                 case kRightArrow:    // scroll bar right arrow
  3874.                     isMotionKey = true;
  3875.                     if ( (pData->hScroll) && (!pData->pKeyEvent) )
  3876.                         {
  3877.                         if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3878.                             HActionProc(pData->hScroll, kControlPageDownPart);
  3879.                         else
  3880.                             HActionProc(pData->hScroll, kControlDownButtonPart);
  3881.                         passToObject = false;
  3882.                         }
  3883.                     break;
  3884.                     }
  3885.         
  3886.             if (passToObject)
  3887.                 anErr = (*(pData->pKeyEvent)) (pWindow, pData, pEvent, isMotionKey);
  3888.             else
  3889.                 {
  3890.                 if ( (pData->documentAcceptsText == false) && !( pEvent->modifiers & cmdKey ) && !(isMotionKey) )
  3891.                     anErr = eDocumentNotModifiable;
  3892.                 }
  3893.             }
  3894.  
  3895.         if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) )
  3896.             ConductErrorDialog(anErr, cTypingCommand, ok);
  3897.             
  3898.         } // (menuResult == 0)
  3899.     
  3900.         
  3901.     return anErr;
  3902.     
  3903. } // DoKeyEvent
  3904.  
  3905. // --------------------------------------------------------------------------------------------------------------
  3906. #pragma segment Main
  3907.  
  3908. OSErr DoAdjustCursor(WindowPtr pWindow, Point *where)
  3909. {
  3910.     OSErr        anErr = noErr;
  3911.     Point        whereMouse;
  3912.     Boolean        didAdjust = false;
  3913.     
  3914.     if (where)
  3915.         whereMouse = *where;
  3916.         
  3917.     if (pWindow)
  3918.         {
  3919.         // not one of our windows?  don't do anything
  3920.         if (GetWindowKind(pWindow) != userKind)
  3921.             didAdjust = true;
  3922.             
  3923.         SetPort((GrafPtr) GetWindowPort(pWindow));
  3924.         
  3925.         if ( (!didAdjust) && (gMachineInfo.haveTSM) )
  3926.             {
  3927.             if (!where)
  3928.                 {
  3929.                 GetMouse(&whereMouse);
  3930.                 LocalToGlobal(&whereMouse);
  3931.                 }
  3932.             if (SetTSMCursor(whereMouse))
  3933.                 didAdjust = true;
  3934.             }
  3935.             
  3936.         if (!didAdjust)
  3937.             {
  3938.             WindowDataPtr    pData = GetWindowInfo(pWindow);
  3939.             RgnHandle        content = NewRgn();
  3940.             Point            globalMouse;
  3941.             
  3942.             SetEmptyRgn(gCursorRgn);
  3943.     
  3944.             if (!where)
  3945.                 GetMouse(&whereMouse);
  3946.             globalMouse = whereMouse;
  3947.             LocalToGlobal(&globalMouse);
  3948.             
  3949.             GetWindowRegion(pWindow, kWindowContentRgn, content);
  3950.             if ((pData) && (PtInRgn(globalMouse, content)) && (PtInRect(whereMouse, &pData->contentRect)))
  3951.                 {
  3952.                 Rect            tempRect;
  3953.                 
  3954.                 tempRect = pData->contentRect;
  3955.                 LocalToGlobal(&TopLeft(tempRect));
  3956.                 LocalToGlobal(&BotRight(tempRect));
  3957.                 RectRgn(gCursorRgn, &tempRect);
  3958.                 
  3959.                 if (pData->pAdjustCursor)
  3960.                     anErr = (*(pData->pAdjustCursor)) (pWindow, pData, &whereMouse, gCursorRgn);
  3961.                 }
  3962.             DisposeRgn(content);
  3963.             }
  3964.         else
  3965.             anErr = eActionAlreadyHandled;
  3966.         }
  3967.     
  3968.     // nobody set the cursor, we do it ourselves
  3969.     if (anErr != eActionAlreadyHandled) {
  3970.         Cursor arrow;
  3971.         SetCursor(GetQDGlobalsArrow(&arrow));
  3972.     }
  3973.         
  3974.     return anErr;
  3975.     
  3976. } // DoAdjustCursor
  3977.  
  3978. // --------------------------------------------------------------------------------------------------------------
  3979. #pragma segment Main
  3980.  
  3981. static long DetermineWaitTime(WindowPtr pWindow)
  3982. {
  3983.     long    waitTime = kMaxWaitTime;
  3984.     
  3985.     while (pWindow)
  3986.         {
  3987.         long            newWaitTime;
  3988.         WindowDataPtr    pData = GetWindowInfo(pWindow);
  3989.         
  3990.         if ((pData) && (pData->pCalculateIdleTime))
  3991.             newWaitTime = (*(pData->pCalculateIdleTime)) (pWindow, pData);
  3992.         else
  3993.             newWaitTime = kMaxWaitTime;
  3994.         
  3995.         if (newWaitTime < waitTime)
  3996.             waitTime = newWaitTime;
  3997.             
  3998.         pWindow = GetNextWindow(pWindow);
  3999.         }
  4000.     
  4001.     return(waitTime);
  4002.     
  4003. } // DetermineWaitTime
  4004.  
  4005. // --------------------------------------------------------------------------------------------------------------
  4006. #pragma segment Main
  4007.  
  4008. static OSStatus GetFinderProcess( ProcessSerialNumber * outPSN )
  4009. {
  4010.     ProcessInfoRec    processInfo;
  4011.     OSErr            outStatus = noErr;
  4012.  
  4013.     outPSN->lowLongOfPSN = 0;
  4014.     outPSN->highLongOfPSN = kNoProcess;
  4015.     
  4016.     processInfo.processInfoLength = sizeof(ProcessInfoRec);
  4017.     processInfo.processName = nil;
  4018.     processInfo.processAppSpec = nil;
  4019.     
  4020.     while( outStatus == noErr )
  4021.     {
  4022.         outStatus = GetNextProcess( outPSN );
  4023.         
  4024.         if( outStatus == noErr )
  4025.         {
  4026.             outStatus = GetProcessInformation( outPSN, &processInfo );
  4027.             if(        (outStatus == noErr)
  4028.                 &&    (processInfo.processSignature == 'MACS')
  4029.                 &&    (processInfo.processType == 'FNDR') )
  4030.             {
  4031.                 break;
  4032.             }
  4033.         }
  4034.     }
  4035.     
  4036.     return outStatus;
  4037. }
  4038.  
  4039. static OSStatus BringFinderToFront(void)
  4040. {
  4041.     OSStatus                outStatus;
  4042.     ProcessSerialNumber        finderProcess;
  4043.     
  4044.     outStatus = GetFinderProcess( &finderProcess );
  4045.     if ( outStatus == noErr )
  4046.     {
  4047.         outStatus = SetFrontProcess( &finderProcess );
  4048.     }
  4049.     
  4050.     return outStatus;
  4051. }
  4052.  
  4053.  
  4054.  
  4055. void HandleEvent(EventRecord * pEvent)
  4056. {
  4057.     WindowPtr    pWindow;
  4058.     Boolean        handled;
  4059.     
  4060.     pWindow    = FrontWindow();
  4061.     handled    = false;
  4062.     
  4063.     switch (pEvent->what)
  4064.         {
  4065.         case kHighLevelEvent:
  4066.             AEProcessAppleEvent(pEvent);
  4067.             break;
  4068.             
  4069.         case osEvt:
  4070.             switch ((pEvent->message >> 24) & 0xFF) /* high byte of message */
  4071.                 {        
  4072.                 case mouseMovedMessage:
  4073.                     DoAdjustCursor(pWindow, nil);
  4074.                     break;
  4075.                     
  4076.                 case suspendResumeMessage:        /* suspend/resume is also an activate/deactivate */
  4077.                     gMachineInfo.amInBackground = (pEvent->message & 1) == 0;
  4078.                     if (pWindow)
  4079.                         DoActivate(pWindow, !gMachineInfo.amInBackground);
  4080.                     break;
  4081.                 }
  4082.             break;
  4083.             
  4084.         case activateEvt:
  4085.             pWindow = (WindowPtr) pEvent->message;
  4086.             DoActivate(pWindow, (pEvent->modifiers & activeFlag) != 0);
  4087.             break;
  4088.                             
  4089.         // disk inserted events must be handled, or uninitialized floppies 
  4090.         // won't be recognized.
  4091.         case diskEvt:
  4092.             if ( HiWord(pEvent->message) != noErr ) 
  4093.                 {
  4094.                 Point    where;
  4095.             
  4096.                 SetPt(&where, 70, 50);
  4097.                 ShowCursor();
  4098.                 (void) DIBadMount(where, pEvent->message);
  4099.                 }        
  4100.             break;
  4101.                 
  4102.         case mouseUp:
  4103.             break;
  4104.             
  4105.         case mouseDown:
  4106.             {
  4107.             short part = FindWindow(pEvent->where, &pWindow);                    
  4108.             
  4109.             DoAdjustCursor(pWindow, &pEvent->where);
  4110.             switch ( part ) 
  4111.                 {
  4112.                 case inContent:
  4113.                     if (pWindow != FrontWindow())
  4114.                         SelectWindow(pWindow);
  4115.                     else
  4116.                         DoContentClick(pWindow);
  4117.                     break;
  4118.                     
  4119.                 case inGoAway:
  4120.                     if (TrackGoAway(pWindow, pEvent->where) )
  4121.                     {
  4122.                         //
  4123.                         // added option-close, because it’s in the HIG
  4124.                         //
  4125.                         if( pEvent->modifiers & optionKey )
  4126.                         {
  4127.                             (void) CloseAllWindows( false );
  4128.                         }
  4129.                         else
  4130.                         {
  4131.                             DoCommand(pWindow, cClose, 0, 0);
  4132.                         }
  4133.                     }
  4134.                     break;
  4135.                     
  4136.                 case inGrow:
  4137.                     DoGrowWindow(pWindow, pEvent);
  4138.                     break;
  4139.                     
  4140.                 case inZoomIn:
  4141.                 case inZoomOut:
  4142.                     if ( TrackBox(pWindow, pEvent->where, part) )
  4143.                         DoZoomWindow(pWindow, part);
  4144.                     break;
  4145.                     
  4146.                 case inProxyIcon:
  4147.                 //
  4148.                 // We’ve seen a hit in the window proxy, so drag the window proxy
  4149.                 //
  4150.                 // We should only be here on a machine with the native window manager
  4151.                 // but we still want to conditionalize it to be fully paraniod
  4152.                 //                
  4153. //                check(gMachineInfo.haveProxyIcons);
  4154.                 {
  4155.                     WindowDataPtr    pData = GetWindowInfo(pWindow);
  4156.                     
  4157.                     if( gMachineInfo.haveProxyIcons && (pData != NULL) )
  4158.                     {
  4159.                         OSStatus        status = TrackWindowProxyDrag( pWindow, pEvent->where );
  4160.                         
  4161.                         if( status == errUserWantsToDragWindow )
  4162.                             handled = false;
  4163.                         else if( status == noErr )
  4164.                             handled = true;
  4165.                     }
  4166.                 }
  4167.                 // fall through
  4168.                 case inDrag:
  4169.                     if( !handled )
  4170.                     {
  4171.                         WindowDataPtr    pData = GetWindowInfo(pWindow);
  4172.                     
  4173.                         //
  4174.                         // Show the file path select popup
  4175.                         //
  4176.                         if( gMachineInfo.haveProxyIcons && (pData != NULL) )
  4177.                         {
  4178.                             if( IsWindowPathSelectClick( pWindow, pEvent ) )
  4179.                             {
  4180.                                 SInt32 itemSelected;
  4181.                             
  4182.                                 if(WindowPathSelect( pWindow, NULL, &itemSelected ) == noErr )
  4183.                                 {
  4184.                                     // switch to the Finder, since the window probably isn’t visible.
  4185.                                     if( LoWord(itemSelected) > 1 )
  4186.                                     {
  4187.                                         BringFinderToFront();
  4188.                                     }
  4189.                                 }
  4190.                                 
  4191.                                 handled = true;
  4192.                             }
  4193.                         }
  4194.                         
  4195.                         if( !handled )
  4196.                         {
  4197.                             BitMap    screenBits;
  4198.                             
  4199.                             GetQDGlobalsScreenBits( &screenBits );
  4200. #if ALLOW_QUICKTIME
  4201.                             if ( (pData) && (pData->dragWindowAligned) )
  4202.                                 DragAlignedWindow((WindowPtr) pWindow, pEvent->where, &screenBits.bounds, nil, nil);
  4203.                             else
  4204.                                 DragWindow(pWindow, pEvent->where, &screenBits.bounds);
  4205. #else
  4206.  
  4207.                             DragWindow(pWindow, pEvent->where, &screenBits.bounds);
  4208.                         }
  4209.                                 
  4210. #endif
  4211.                     }
  4212.                     break;
  4213.                 
  4214.                 case inMenuBar:                /* process a mouse menu command (if any) */
  4215.                     {
  4216.                     long            menuResult;
  4217.                     WindowDataPtr    pData;
  4218.                     
  4219.                     // force these threads to run to completion so the
  4220.                     // contents of the menus are fully initialized
  4221.                     
  4222.                     if (gFontThread != kNoThreadID)
  4223.                         {
  4224.                         gDontYield = true;
  4225.                         SetThreadState(gFontThread, kReadyThreadState, gFontThread);
  4226.                         YieldToThread(gFontThread);
  4227.                         gDontYield = false;
  4228.                         }
  4229.                     
  4230.                     pWindow = FrontWindow();
  4231.                     pData = GetWindowInfo(pWindow);
  4232.                     if ((pData) && (pData->pPreMenuAccess))
  4233.                         (void) (*(pData->pPreMenuAccess)) (pWindow, pData);
  4234.                     AdjustMenus(pWindow, true, false);
  4235.                     InitCursor();
  4236.                     menuResult = MenuSelect(pEvent->where);
  4237.                     if ( (gMachineInfo.haveTSM) && (TSMMenuSelect(menuResult)) )
  4238.                         HiliteMenu(0);
  4239.                     else
  4240.                         DoMenuCommand(pWindow, menuResult, 0);
  4241.                     }
  4242.                     break;
  4243.                     
  4244.                 case inSysWindow:            /* let the system handle the mouseDown */
  4245.                     SystemClick(pEvent, pWindow);
  4246.                     break;
  4247.                     
  4248.                 } // switch(part)
  4249.             }
  4250.             break;
  4251.             
  4252.         case keyDown:
  4253.         case autoKey:                        /* check for menukey equivalents */
  4254.             DoKeyEvent(pWindow, pEvent, true);
  4255.             break;
  4256.             
  4257.         case updateEvt:
  4258.             pWindow = (WindowPtr) pEvent->message;
  4259.             DoUpdateWindow(pWindow);
  4260.             break;
  4261.  
  4262.         } // switch (pEvent->what)
  4263.     
  4264. } // HandleEvent
  4265.  
  4266. // -----------------------------------------------------------------------------------------------------------
  4267.  
  4268. #pragma segment Main
  4269.  
  4270. static void SynchronizeFiles( void )
  4271. {
  4272.     //
  4273.     // File synchronization for all document windows
  4274.     //
  4275.     static UInt32            nextSynchTicks = 10;
  4276.     UInt32                    currentTicks = TickCount();
  4277.     WindowPtr                currentWindow = FrontWindow();
  4278.     
  4279.     // only synchronize every so often...
  4280.     if( currentTicks > nextSynchTicks )
  4281.     {
  4282.         //
  4283.         // Loop over all our document windows,
  4284.         // searching for files whose locations have changed
  4285.         //
  4286.         while ( currentWindow != NULL )
  4287.         {
  4288.             WindowDataPtr    documentWindowData = GetWindowInfo(currentWindow);
  4289.             
  4290.             //
  4291.             // If it's a SimpleText-owned window and it has an associated file...
  4292.             //
  4293.             if( (documentWindowData != NULL)
  4294.                    && (documentWindowData->dataRefNum != -1) )
  4295.             {
  4296.                 Boolean        wasChanged = false;
  4297.                 FSSpec        newSpec;
  4298.                 FolderType    folder = 0;
  4299.                 
  4300.                 //
  4301.                 // Ask the Alias Manager where the window went
  4302.                 //
  4303.                 (void) ResolveAlias( NULL, documentWindowData->fileAlias, &newSpec, &wasChanged );
  4304.                 if( wasChanged )
  4305.                 {
  4306.                     //
  4307.                     // The file location has changed; update the window
  4308.                     //
  4309.                     documentWindowData->fileSpec = newSpec;
  4310.                     
  4311.                     // user might have renamed the file 
  4312.                     SetWTitle( currentWindow, newSpec.name );
  4313.                     
  4314.                     //
  4315.                     // Close the window if the user moved the Is it in the trash?
  4316.                     //
  4317.                     IdentifyFolder( newSpec.vRefNum, newSpec.parID, &folder );
  4318.                     
  4319.                     if( folder == kTrashFolderType )
  4320.                     {
  4321.                         DoCloseWindow( currentWindow, false, 0 );    // false->not quitting
  4322.                     }
  4323.                 }
  4324.             }
  4325.                 
  4326.             currentWindow = GetNextWindow( currentWindow );
  4327.         }
  4328.         
  4329.         //
  4330.         // To avoid flooding the CPU, wait at least one second
  4331.         // between file synch checks 
  4332.         //
  4333.         nextSynchTicks = ( currentTicks + 60 );
  4334.     }
  4335. }
  4336.  
  4337.  
  4338. static OSErr    DoEventLoop(void)
  4339. {
  4340.     OSErr        anErr = noErr;
  4341.     Boolean        gotEvent;
  4342.     Boolean        trueGotEvent;
  4343.     WindowPtr    pWindow;
  4344.     
  4345.     do
  4346.     {
  4347.         pWindow = GetWindowList();    // walk all of our windows, even invisible ones
  4348.         
  4349.         /*
  4350.             We used to call DoAdjustCursor every time through the event loop, but that produced
  4351.             nasty cursor flickering when using the magic marker cursor over GX documents. We're
  4352.             now smarter and allow the adjustCursor callback to manipulate the cursor region.
  4353.             However, there may still be cases where the cursor doesn't get adjusted properly.
  4354.             If you suspect a cursor adjustment problem, try putting this call to DoAdjustCursor
  4355.             back in and see what the cursor does. Then fix the code to accurately maintain the
  4356.             cursor region and remove the DoAdjustCursor call. -ecs 11/25/96
  4357.         */
  4358.         // DoAdjustCursor(pWindow, nil);
  4359.         gotEvent = WaitNextEvent(everyEvent, &gEvent, DetermineWaitTime(pWindow), gCursorRgn);
  4360.         trueGotEvent = gotEvent;
  4361.  
  4362.         //
  4363.         // Synchronize all files on every event
  4364.         //
  4365.         SynchronizeFiles();
  4366.  
  4367.         // WNE may close the window if it's owned by some silly extension.
  4368.         pWindow = GetWindowList();        
  4369.         
  4370.         // let text services handle the event first if it wishes to do so
  4371.         if ( gMachineInfo.haveTSM )
  4372.             {
  4373.             ScriptCode    keyboardScript;
  4374.             WindowPtr    theFront = FrontWindow();
  4375.             
  4376.             if (theFront)
  4377.                 {
  4378.                                 CGrafPtr fPort = GetWindowPort(theFront);
  4379.                 SetPort((GrafPtr) fPort);
  4380.                 
  4381.                 keyboardScript = GetScriptManagerVariable(smKeyScript);
  4382.                                 if (FontToScript(GetPortTextFont(fPort)) != keyboardScript)
  4383.                     TextFont(GetScriptVariable(keyboardScript, smScriptAppFond));
  4384.                 }
  4385.             
  4386.             if (TSMEvent(&gEvent))
  4387.                 gotEvent = false;
  4388.             }
  4389.             
  4390.         // let all windows filter this event, and get time if they wish to
  4391.         while (pWindow)
  4392.             {
  4393.             WindowDataPtr    pData = GetWindowInfo(pWindow);
  4394.             Boolean            finishedEvent = false;
  4395.                                 
  4396.             // if we hit a window we know about, then do filtering
  4397.             if (pData)
  4398.                 {
  4399.                 if (pData->pFilterEvent)
  4400.                     finishedEvent = (*(pData->pFilterEvent)) (pWindow, pData, &gEvent);
  4401.                 }
  4402.  
  4403.             // if filtering indicates complete handling of event, then stop, and
  4404.             // do no regular processing.
  4405.             if (finishedEvent)
  4406.                 {
  4407.                 gotEvent = false;
  4408.                 pWindow = nil;
  4409.                 }
  4410.             else
  4411.                 pWindow = GetNextWindow(pWindow);
  4412.             }
  4413.             
  4414.         if (gotEvent)
  4415.             HandleEvent(&gEvent);
  4416.             
  4417.         // close request?
  4418.         if (gAllDone)
  4419.         {
  4420.             gAllDone = CloseAllWindows( true );
  4421.         }
  4422.         
  4423.         // our threads are low-priority, so we only give time to them on idle
  4424.         if (gMachineInfo.haveThreads && !trueGotEvent && !gAllDone)
  4425.             YieldToAnyThread();
  4426.         
  4427.         } while (!gAllDone);
  4428.         
  4429.     return anErr;
  4430.     
  4431. } // DoEventLoop
  4432.  
  4433.  
  4434. //
  4435. // Close all windows
  4436. //
  4437. // Returns false to cancel
  4438. //
  4439. static Boolean CloseAllWindows( Boolean quitting )
  4440. {
  4441.     WindowPtr    pWindow, nextWindow;
  4442.     OSStatus    closeError;
  4443.     Boolean        notCanceled = true;
  4444.     
  4445.     pWindow = FrontWindow();
  4446.     while ( (pWindow != NULL) && notCanceled )
  4447.     {
  4448.         nextWindow = GetNextWindow(pWindow);
  4449.         closeError = DoCloseWindow(pWindow, quitting, false);
  4450.         
  4451.         // ••• why not just require the window to always return an error if it doesn’t close?
  4452.         
  4453.         // window didn't close?  then don't quit
  4454.         if (pWindow == FrontWindow())
  4455.             notCanceled = false;
  4456.             
  4457.         // something bad happened, then don't quit
  4458.         if ( closeError != noErr )
  4459.             notCanceled = false;
  4460.             
  4461.         pWindow = nextWindow;
  4462.     }
  4463.     
  4464.     return notCanceled;
  4465. }
  4466.  
  4467. // --------------------------------------------------------------------------------------------------------------
  4468. // DRAG MANAGEMENT GLOBAL SUPPORT ROUTINES
  4469. // --------------------------------------------------------------------------------------------------------------
  4470.  
  4471. // Globals for our drag handlers
  4472.  
  4473. Boolean                gCanAccept;                // if we can receive the item(s) being dragged
  4474.  
  4475. // --------------------------------------------------------------------------------------------------------------
  4476. #pragma segment Drag
  4477.  
  4478. static pascal OSErr GlobalTrackingHandler(short message, WindowPtr pWindow, void *handlerRefCon, DragReference theDragRef)
  4479. {
  4480.     #pragma unused(handlerRefCon)
  4481.  
  4482.     WindowDataPtr pData = GetWindowInfo(pWindow);
  4483.  
  4484.     // Call the tracking handler associated with this type of window. Only allow messages referencing
  4485.     // a specific window to be passed to the handler.
  4486.  
  4487.     if (pData)
  4488.         {    
  4489.         if (pData->pDragTracking)
  4490.             return ((*(pData->pDragTracking)) (pWindow, pData, theDragRef, message));
  4491.         }
  4492.     
  4493.     return noErr;
  4494.  
  4495. } // GlobalTrackingHandler
  4496.  
  4497. DragTrackingHandlerUPP gGlobalTrackingHandler;
  4498.  
  4499. // --------------------------------------------------------------------------------------------------------------
  4500. #pragma segment Drag
  4501.  
  4502. static pascal OSErr GlobalReceiveHandler(WindowPtr pWindow, void *handlerRefCon, DragReference theDragRef)
  4503. {
  4504.     #pragma unused(handlerRefCon)
  4505.  
  4506.     WindowDataPtr pData = GetWindowInfo(pWindow);
  4507.     
  4508.     if (pData)
  4509.         {
  4510.         if (pData->pDragTracking)
  4511.             return ((*(pData->pDragReceive)) (pWindow, pData, theDragRef));
  4512.         }
  4513.  
  4514.     return noErr;
  4515.  
  4516. } // GlobalReceiveHandler
  4517.  
  4518. DragReceiveHandlerUPP gGlobalReceiveHandler;
  4519.  
  4520. // --------------------------------------------------------------------------------------------------------------
  4521. //
  4522. // IsOnlyThisFlavor - Given a DragReference and a FlavorType, we iterate through the drag items to determine if
  4523. //                      all are of flavor theType. If this is so, we return true. If any of the items are not
  4524. //                      theType, we return false, indicating that we should not accept the drag.
  4525. //
  4526. #pragma segment Drag
  4527.  
  4528. Boolean IsOnlyThisFlavor(DragReference theDragRef, FlavorType theType)
  4529. {
  4530.     unsigned short    items, index;
  4531.     FlavorFlags        theFlags;
  4532.     ItemReference    itemID;
  4533.     OSErr            anErr = noErr;
  4534.  
  4535.     CountDragItems(theDragRef, &items);
  4536.     
  4537.     for(index = 1; index <= items; index++)
  4538.         {
  4539.         GetDragItemReferenceNumber(theDragRef, index, &itemID);
  4540.  
  4541.         anErr = GetFlavorFlags(theDragRef, itemID, theType, &theFlags);
  4542.         if(anErr == noErr)
  4543.             continue;    // it's okay, this flavor is cool
  4544.  
  4545.         return false;    // this item has at least one flavor we don't like
  4546.         }
  4547.  
  4548.     return true;        // all flavors in this item were cool
  4549.  
  4550. } // IsOnlyThisFlavor
  4551.  
  4552. // --------------------------------------------------------------------------------------------------------------
  4553. //
  4554. // IsDropInFinderTrash - Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash.
  4555. //
  4556. #pragma segment Drag
  4557.  
  4558. Boolean IsDropInFinderTrash(AEDesc *dropLocation)
  4559. {
  4560.     OSErr            result;
  4561.     AEDesc            dropSpec;
  4562.     FSSpec            *theSpec;
  4563.     CInfoPBRec        thePB;
  4564.     short            trashVRefNum;
  4565.     long            trashDirID;
  4566.  
  4567.     //    Coerce the dropLocation descriptor into an FSSpec. If there's no dropLocation or
  4568.     //    it can't be coerced into an FSSpec, then it couldn't have been the Trash.
  4569.  
  4570.     if ((dropLocation->descriptorType != typeNull) &&
  4571.         (AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) 
  4572.         {
  4573.         AEGetDescData(dropLocation, typeFSS, &theSpec, sizeof(FSSpec) );
  4574.  
  4575.         //    Get the directory ID of the given dropLocation object.
  4576.  
  4577.         thePB.dirInfo.ioCompletion = 0L;
  4578.         thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name;
  4579.         thePB.dirInfo.ioVRefNum = theSpec->vRefNum;
  4580.         thePB.dirInfo.ioFDirIndex = 0;
  4581.         thePB.dirInfo.ioDrDirID = theSpec->parID;
  4582.  
  4583.         result = PBGetCatInfoSync(&thePB);
  4584.  
  4585.         AEDisposeDesc(&dropSpec);
  4586.  
  4587.         if (result != noErr)
  4588.             return false;
  4589.  
  4590.         //    If the result is not a directory, it must not be the Trash.
  4591.  
  4592.         if (!(thePB.dirInfo.ioFlAttrib & (1 << 4)))
  4593.             return false;
  4594.  
  4595.         //    Get information about the Trash folder.
  4596.  
  4597.         FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID);
  4598.  
  4599.         //    If the directory ID of the dropLocation object is the same as the directory ID
  4600.         //    returned by FindFolder, then the drop must have occurred into the Trash.
  4601.  
  4602.         if (thePB.dirInfo.ioDrDirID == trashDirID)
  4603.             return true;
  4604.         }
  4605.  
  4606.     return false;
  4607.  
  4608. } // IsDropInFinderTrash
  4609.  
  4610. // --------------------------------------------------------------------------------------------------------------
  4611. // APPLE EVENT SUPPORT ROUTINES
  4612. // --------------------------------------------------------------------------------------------------------------
  4613. #pragma segment Main
  4614.  
  4615. static OSErr    MissingParameterCheck(
  4616.     const AppleEvent     *inputEvent)
  4617. /*
  4618.     This routine checks an input AppleEvent for the missing keyword.
  4619.     If the missing keyword is found, that means that some required
  4620.     parameters were missing (ie, an error). 
  4621.     
  4622.     However, if the missing keyword isn't found, that means that we aren't missing 
  4623.     any required parameters (that is to say, all REQUIRED parameters were supplied
  4624.     by the person who created the event).
  4625.     
  4626.     SOME DAY, THE ABOVE COMMENT WILL MAKE SENSE TO YOU.  IT STILL DOESN'T
  4627.     TO ME AND I WAS THE ONE WHO WROTE IT.
  4628. */
  4629. {
  4630.     OSErr        anErr;
  4631.     AEKeyword    missingKeyword;
  4632.     DescType    ignoredActualType;
  4633.     Size        ignoredActualSize;
  4634.     
  4635.     anErr = AEGetAttributePtr(
  4636.         inputEvent, 
  4637.         keyMissedKeywordAttr,
  4638.         typeWildCard,
  4639.         &ignoredActualType,
  4640.         (Ptr) &missingKeyword,
  4641.         sizeof(AEKeyword),
  4642.         &ignoredActualSize);
  4643.             
  4644.     if (anErr == noErr)
  4645.         anErr = errAEParamMissed;
  4646.     else
  4647.         if (anErr == errAEDescNotFound)
  4648.             anErr = noErr;
  4649.         
  4650.     return anErr;
  4651.     
  4652. } // MissingParameterCheck
  4653.  
  4654.  
  4655. // --------------------------------------------------------------------------------------------------------------
  4656. #pragma segment Main
  4657.  
  4658. static pascal OSErr    DoOpenApp(
  4659.     const AppleEvent     *inputEvent,
  4660.     AppleEvent     *outputEvent,
  4661.     UInt32        handlerRefCon)
  4662. {
  4663. #pragma unused (outputEvent, handlerRefCon)
  4664.  
  4665.     DoCommand(nil, cNew, 0, 0);
  4666.     
  4667.     // so that the initial document opens more quickly, we don't start
  4668.     // the threads until we get an OpenApp or OpenDocument AppleEvent
  4669.     if (gStarterThread != kNoThreadID)
  4670.         SetThreadState(gStarterThread, kReadyThreadState, gStarterThread);
  4671.     
  4672.     return(MissingParameterCheck(inputEvent));
  4673.     
  4674. } // DoOpenApp
  4675.  
  4676. // --------------------------------------------------------------------------------------------------------------
  4677. #pragma segment Main
  4678.  
  4679. static pascal OSErr    DoReopenApp(
  4680.     const AppleEvent     *inputEvent,
  4681.     AppleEvent     *outputEvent,
  4682.     UInt32        handlerRefCon)
  4683. {
  4684. #pragma unused (outputEvent, handlerRefCon)
  4685.  
  4686.     if (FrontWindow() == nil)
  4687.         DoCommand(nil, cNew, 0, 0);
  4688.     
  4689.     return(MissingParameterCheck(inputEvent));
  4690.     
  4691. } // DoReopenApp
  4692.  
  4693. // --------------------------------------------------------------------------------------------------------------
  4694. #pragma segment Main
  4695.  
  4696. static pascal OSErr    DoQuitApp(
  4697.     const AppleEvent     *inputEvent,
  4698.     AppleEvent     *outputEvent,
  4699.     UInt32        handlerRefCon)
  4700. {
  4701. #pragma unused (outputEvent, handlerRefCon)
  4702.  
  4703.     DoCommand(nil, cQuit, 0, 0);
  4704.  
  4705.     return(MissingParameterCheck(inputEvent));
  4706.     
  4707. } // DoQuitApp
  4708.  
  4709. #if 0    // AEC, it does not appear this is ever called.  Do we need it?
  4710. WindowPtr OpenDoc(short DocKind, FSSpec *spec, StringPtr pass)
  4711. {       
  4712.     OSErr    anErr;
  4713.     Boolean        wasAlreadyOpen;
  4714.     FInfo    theFileInfo; 
  4715.  
  4716.     anErr = FSpGetFInfo(spec, &theFileInfo);
  4717.     if (anErr == noErr)
  4718.         anErr = DetermineWindowTypeOrOpen(spec, theFileInfo.fdType, nil, nil, &wasAlreadyOpen);
  4719.  
  4720.     return(NULL);    // sorry, we won't tell you if it was successful
  4721. }
  4722. #endif // AEC
  4723.  
  4724. // --------------------------------------------------------------------------------------------------------------
  4725. #pragma segment Main
  4726. // AEC, changed prototype to match headers
  4727. static pascal OSErr    DoOpenOrPrint(
  4728.     const AppleEvent     *inputEvent,
  4729.     StringPtr    pPrinterName)    // nil == 0, zero length == print to default, other == printer name
  4730. {
  4731.  
  4732.     OSErr        anErr, anErr2;
  4733.     AEDescList    docList;                // list of docs passed in
  4734.     long        index, itemsInList;
  4735.     void*        hPrint = 0;
  4736.     Boolean        wasAlreadyOpen;
  4737.     
  4738.     anErr = AEGetParamDesc( inputEvent, keyDirectObject, typeAEList, &docList);
  4739.     nrequire(anErr, GetFileList);
  4740.  
  4741.     anErr = AECountItems( &docList, &itemsInList);            // how many files passed in
  4742.     nrequire(anErr, CountDocs);
  4743.     for (index = 1; index <= itemsInList; index++)            // handle each file passed in
  4744.         {    
  4745.         AEKeyword    keywd;
  4746.         DescType    returnedType;
  4747.         Size        actualSize;
  4748.         FSSpec        theFSS;    
  4749.  
  4750.         anErr = AEGetNthPtr( &docList, index, typeFSS, &keywd, &returnedType,    // get file's info
  4751.                             (Ptr)(&theFSS), sizeof(theFSS), &actualSize);
  4752.         nrequire(anErr, AEGetNthPtr);
  4753.         
  4754.         {
  4755.         FInfo    theFileInfo;
  4756.         
  4757.         anErr = FSpGetFInfo(&theFSS, &theFileInfo);
  4758.         if (anErr == noErr)
  4759.             anErr = DetermineWindowTypeOrOpen(&theFSS, theFileInfo.fdType, nil, nil, &wasAlreadyOpen);
  4760.             
  4761.         if (anErr == eDocumentWrongKind)
  4762.             {
  4763.             if (pPrinterName)
  4764.                 ConductErrorDialog(anErr, cPrint, cancel);
  4765.             else
  4766.                 ConductErrorDialog(anErr, cOpen, cancel);
  4767.  
  4768.             anErr = noErr;
  4769.             break;
  4770.             }
  4771.             
  4772.         nrequire(anErr, DetermineWindowTypeOrOpen);
  4773.         }
  4774.         
  4775.         if (pPrinterName)
  4776.             {
  4777.             WindowPtr        pWindow = FrontWindow();
  4778.             WindowDataPtr    pData = GetWindowInfo(pWindow);
  4779.             
  4780.             if (pData->pPrintPage)
  4781.                 {
  4782.                 if (index == 1)
  4783.                     {
  4784.                         anErr = DoPrintSetup(pWindow, pPrinterName);
  4785.                     
  4786.                         if (anErr == noErr)
  4787.                         anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, false);
  4788.                     }
  4789.                 }
  4790.             
  4791.             if (!wasAlreadyOpen)
  4792.                 DoCloseWindow(pWindow, false, 0);
  4793.  
  4794.             if (anErr != noErr)
  4795.                 break;
  4796.             }
  4797.         }
  4798.  
  4799.     // finally, make sure we didn't miss any parameters
  4800.     anErr2 = MissingParameterCheck(inputEvent);
  4801.     if (anErr == noErr)
  4802.         anErr = anErr2;
  4803.         
  4804. // FALL THROUGH EXCEPTION HANDLING
  4805. DetermineWindowTypeOrOpen:
  4806. AEGetNthPtr:
  4807. CountDocs:
  4808.     // done with doc list
  4809.     (void) AEDisposeDesc( &docList);                        
  4810.     
  4811. GetFileList:
  4812.  
  4813.     // don't report cancels from prints
  4814.     if (pPrinterName)
  4815.         {
  4816.         if (anErr == kPMCancel)
  4817.             anErr = noErr;
  4818.         }
  4819.     
  4820.     if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) && (anErr != eUserCanceled) )
  4821.         {
  4822.         if (pPrinterName)
  4823.             ConductErrorDialog(anErr, cPrint, cancel);
  4824.         else
  4825.             ConductErrorDialog(anErr, cOpen, cancel);
  4826.         }
  4827.         
  4828.     return anErr;
  4829.     
  4830. } // DoOpenOrPrint
  4831.  
  4832. // --------------------------------------------------------------------------------------------------------------
  4833. #pragma segment Main
  4834.  
  4835. static pascal OSErr    DoOpenDocument(
  4836.     const AppleEvent     *inputEvent,
  4837.     AppleEvent     *outputEvent,
  4838.     UInt32        handlerRefCon)
  4839. {
  4840. #pragma unused (outputEvent, handlerRefCon)
  4841.  
  4842.     OSErr        anErr;
  4843.     
  4844.     if (IsCommandEnabled(cOpen))
  4845.         {
  4846.         anErr = DoOpenOrPrint(inputEvent, nil);
  4847.         }
  4848.     else
  4849.         {
  4850.         anErr = errAEEventNotHandled;
  4851.         ConductErrorDialog(anErr, cOpen, cancel);
  4852.         }
  4853.         
  4854.     // so that the initial document opens more quickly, we don't start
  4855.     // the threads until we get an OpenApp or OpenDocument AppleEvent
  4856.     if (gStarterThread != kNoThreadID)
  4857.         SetThreadState(gStarterThread, kReadyThreadState, gStarterThread);
  4858.     
  4859.     return anErr;
  4860.     
  4861. } // DoOpenDocument
  4862.  
  4863. // --------------------------------------------------------------------------------------------------------------
  4864. #pragma segment Main
  4865.  
  4866. static pascal OSErr    DoPrintDocument(
  4867.     const AppleEvent     *inputEvent,
  4868.     AppleEvent     *outputEvent,
  4869.     UInt32        handlerRefCon)
  4870. {
  4871. #pragma unused (outputEvent, handlerRefCon)
  4872.     OSErr        anErr;
  4873.     FSSpec        printerFSS;
  4874.     AEDescList    dtpList;                // list of docs passed in
  4875.     
  4876.     if (IsCommandEnabled(cOpen))
  4877.         {
  4878.         // try to find out if this doc was dropped onto a printer
  4879.         anErr = AEGetAttributeDesc( inputEvent, keyOptionalKeywordAttr, typeAEList, &dtpList);
  4880.     
  4881.         if (anErr == noErr)                                            // doc dragged to dtp?
  4882.             {
  4883.             AEKeyword    keywd;
  4884.             DescType    returnedType;
  4885.             Size        actualSize;
  4886.     
  4887.             anErr = AEGetNthPtr( &dtpList, 1, typeFSS, &keywd, &returnedType,    // get dtp info
  4888.                             (Ptr)(&printerFSS), sizeof(printerFSS), &actualSize);
  4889.             }
  4890.             
  4891.         // if it wasn't, that's not an error, just print normally
  4892.         if (anErr != noErr)
  4893.             {
  4894.             printerFSS.name[0] = 0;
  4895.             anErr = noErr;
  4896.             }
  4897.             
  4898.         anErr = DoOpenOrPrint(inputEvent, &printerFSS.name[0]);
  4899.         }
  4900.     else
  4901.         {
  4902.         anErr = errAEEventNotHandled;
  4903.         ConductErrorDialog(anErr, cPrint, cancel);
  4904.         }
  4905.         
  4906.     return anErr;
  4907.     
  4908. } // DoPrintDocument
  4909.  
  4910.  
  4911. // --------------------------------------------------------------------------------------------------------------
  4912. #pragma segment Main
  4913.  
  4914. // --------------------------------------------------------------------------------------------------------------
  4915. // MAIN INITIALIZE/SHUTDOWN/LOOP ROUTINES
  4916. // --------------------------------------------------------------------------------------------------------------
  4917. #pragma segment Main
  4918.  
  4919. // --------------------------------------------------------------------------------------------------------------
  4920. #pragma segment Initialize
  4921.         
  4922. // --------------------------------------------------------------------------------------------------------------
  4923. // must be in Main because it runs in a thread and we don't want the segment unloaded
  4924. // while some other thread is running
  4925. #pragma segment Main
  4926.  
  4927. // --------------------------------------------------------------------------------------------------------------
  4928. // must be in Main because it runs in a thread and we don't want the segment unloaded
  4929. // while some other thread is running
  4930. #pragma segment Main
  4931.  
  4932. #if 0
  4933. static long SortAndAddMenu(MenuHandle menu, Str255 newItem)
  4934. {
  4935.     short    numInMenu = CountMItems(menu);
  4936.     short    i;
  4937.     Str255    oldItem;
  4938.     
  4939.     for (i = 1; i <= numInMenu; ++i)
  4940.         {
  4941.         GetMenuItemText(menu, i, oldItem);
  4942.         switch(IUCompString(newItem, oldItem))
  4943.             {
  4944.             // already in?  Return index
  4945.             case 0:
  4946.                 return(i);
  4947.                 break;
  4948.                 
  4949.             // less than, keep scanning
  4950.             case 1:
  4951.                 break;
  4952.                 
  4953.             // greater than, add back one
  4954.             case -1:
  4955.                 InsertMenuItem(menu, "\pTom Dowdy", i-1);
  4956.                 SetMenuItemText(menu, i, newItem);
  4957.                 return(i);
  4958.                 break;
  4959.             }
  4960.         }
  4961.         
  4962.     // fall off the end?  add at the end
  4963.     InsertMenuItem(menu, "\pTom Dowdy", numInMenu);
  4964.     SetMenuItemText(menu, numInMenu+1, newItem);
  4965.             
  4966.     return(numInMenu+1);
  4967.     
  4968. } // SortAndAddMenu
  4969. #endif
  4970.  
  4971. // must be in Main because it runs in a thread and we don't want the segment unloaded
  4972. // while some other thread is running
  4973. #pragma segment Initialize
  4974.  
  4975. static OSErr BuildFontMenu(MenuHandle menu)
  4976. {
  4977.     OSErr    anErr = noErr;
  4978.     
  4979.     AppendResMenu(menu, 'FONT');
  4980.     
  4981.     return(anErr);
  4982.     
  4983. } // BuildFontMenu
  4984.  
  4985. // --------------------------------------------------------------------------------------------------------------
  4986. // structures for FastGetNewMBar
  4987.  
  4988. typedef struct
  4989. {
  4990.     MenuHandle    menuOH;
  4991.     short        menuLeft;
  4992. }
  4993. MenuRec;
  4994.  
  4995. typedef struct
  4996. {
  4997.     short        lastMenu;
  4998.     short        lastRight;
  4999.     short        mbResID;
  5000.     MenuRec        menu[1];
  5001. }
  5002. DynamicMenuList;
  5003.  
  5004. // --------------------------------------------------------------------------------------------------------------
  5005. #pragma segment Initialize
  5006.  
  5007. /*
  5008.     A much faster implementation of GetNewMBar, cuts about 0.3 second off the boot time on a 7500/100 running 7.5.5.
  5009.     
  5010.     DISABLED THIS CODE, APPLEGUIDE DEPENDS UPON INSERTMENU, WHICH THIS DOESN'T CALL.  STILL, THIS WOULD BE NICE
  5011.     TO DO AT SOME TIME!
  5012. */
  5013. #if 0
  5014. static Handle FastGetNewMBar(short id)
  5015. {
  5016.     Handle                hMbar;
  5017.     short                cMenus;
  5018.     int                    iMenu;
  5019.     MenuHandle            hmenu;
  5020.     DynamicMenuList**    hmenulist;
  5021.     
  5022.     hMbar = GetResource('MBAR', id);
  5023.     require(hMbar != NULL, GetResource);
  5024.     
  5025.     cMenus = *(short*) *hMbar;
  5026.     hmenulist = (DynamicMenuList**) NewHandleClear(sizeof(DynamicMenuList) + sizeof(MenuRec) * cMenus);
  5027.     require(hmenulist != NULL, NewMenuList);
  5028.         
  5029.     for (iMenu = 0; iMenu < cMenus; iMenu++)
  5030.         {
  5031.         hmenu = GetMenu(*(short*) ((BytePtr) *hMbar + 2 + 2 * iMenu));
  5032.         if (hmenu != NULL)
  5033.             (*hmenulist)->menu[iMenu].menuOH = hmenu;
  5034.         }
  5035.         
  5036.     ReleaseResource(hMbar);
  5037.     
  5038.     (*hmenulist)->lastMenu = cMenus * 6;
  5039.     return (Handle) hmenulist;
  5040.     
  5041.  
  5042. // EXCEPTION HANDLING
  5043. NewMenuList:
  5044.     ReleaseResource(hMbar);
  5045. GetResource:
  5046.  
  5047.     return NULL;
  5048.         
  5049. } // FastGetNewMBar
  5050. #endif
  5051.  
  5052. // --------------------------------------------------------------------------------------------------------------
  5053. #pragma segment Initialize
  5054.  
  5055. static OSErr    DoInitialize(void)
  5056. {
  5057. //    short                count;            // loop counter
  5058.     Handle                menuBar;        // for loading our menus in
  5059.     OSErr        anErr = noErr;    // any errors we get, none so far
  5060.     long                version;        // version for Gestalt calls
  5061.     
  5062.     
  5063.     gMachineInfo.haveAppearanceMgr    = (Gestalt(gestaltAppearanceAttr, &version) == noErr) && ((version & (1<<gestaltAppearanceExists)) != 0);
  5064.     if (gMachineInfo.haveAppearanceMgr)
  5065.         RegisterAppearanceClient();
  5066.  
  5067. #if 0        
  5068.     InitGraf((Ptr) &FrontWindow());
  5069.     InitFonts();
  5070.     InitWindows();
  5071.     InitMenus();
  5072.     TEInit();
  5073.     InitDialogs(nil);
  5074.     InitCursor();
  5075. #endif
  5076.  
  5077.     InitCursor();
  5078.     //InitializeQTML( 0 );
  5079.     
  5080.     gAllDone = false;
  5081.     
  5082.     gMachineInfo.lastBalloonIndex = iNoBalloon;
  5083.     gMachineInfo.amInBackground = false;
  5084.     gMachineInfo.documentCount  = 1;
  5085. #if ALLOW_QUICKTIME
  5086.     gMachineInfo.haveQuickTime     = (Gestalt(gestaltQuickTime, &version) == noErr);
  5087. #else
  5088.     gMachineInfo.haveQuickTime = false;
  5089. #endif
  5090.     gMachineInfo.haveRecording     = (Gestalt(gestaltSoundAttr, &version) == noErr) && ((version & (1<<gestaltHasSoundInputDevice)) != 0);
  5091.     gMachineInfo.haveTTS         = (Gestalt(gestaltSpeechAttr, &version) == noErr) && ((version & (1<<gestaltSpeechMgrPresent)) != 0);
  5092.     gMachineInfo.haveTSM         = (Gestalt(gestaltTSMgrVersion, &version) == noErr) && (version >= 1);
  5093.     gMachineInfo.haveTSMTE         = (Gestalt(gestaltTSMTEAttr, &version) == noErr) && ((version & (1<<gestaltTSMTE)) != 0);
  5094.     gMachineInfo.haveDragMgr    = (Gestalt(gestaltDragMgrAttr, &version) == noErr) && ((version & (1<<gestaltDragMgrPresent)) != 0) &&
  5095.                                     (Gestalt(gestaltTEAttr, &version) == noErr) && ((version & (1<<gestaltTEHasGetHiliteRgn)) != 0);
  5096.     gMachineInfo.haveThreeD        = false;
  5097.     gMachineInfo.haveAppleGuide    = (Gestalt(gestaltHelpMgrAttr, &version) == noErr) && ((version & (1<<gestaltAppleGuidePresent)) != 0);
  5098.     gMachineInfo.haveThreads    = (Gestalt(gestaltThreadMgrAttr, &version) == noErr) && ((version & (1<<gestaltThreadMgrPresent)) != 0);
  5099.     
  5100.     gMachineInfo.haveNavigationServices  = NavServicesAvailable();
  5101.  
  5102.     //
  5103.     // Record the presence of >= 8.5 window manager features.
  5104.     //
  5105.     gMachineInfo.haveProxyIcons = false;
  5106.     gMachineInfo.haveFloatingWindows = false;
  5107.     
  5108. #if TARGET_CPU_PPC
  5109.  
  5110.     //
  5111.     if( ( Gestalt( gestaltWindowMgrAttr, &version ) == noErr ) )
  5112.     {
  5113.         if( version & (1L << gestaltWindowMgrPresentBit) )
  5114.         {
  5115.             gMachineInfo.haveProxyIcons = true;
  5116.         
  5117.             if( version & (1L << gestaltHasFloatingWindows) )
  5118.                 gMachineInfo.haveFloatingWindows = true;
  5119.         }
  5120.     }
  5121. #endif
  5122.  
  5123.  
  5124.     // initialize text services if they exist
  5125.     if (gMachineInfo.haveTSMTE)
  5126.         {
  5127.         if (InitTSMAwareApplication() != noErr)
  5128.             {
  5129.             gMachineInfo.haveTSM = false;
  5130.             gMachineInfo.haveTSMTE = false;
  5131.             }
  5132.         }
  5133.         
  5134.     // save away info we need from the get-go    
  5135.     gApplicationResFile = CurResFile();
  5136.     gCursorRgn = NewRgn();
  5137.  
  5138.     // load up the menus
  5139.     menuBar = (Handle) GetNewMBar(rMenuBar);    /* read menus into menu bar */
  5140.     anErr = ResError();
  5141.     if ( (anErr == noErr) && (menuBar == nil) )
  5142.         anErr = resNotFound;
  5143.     nrequire(anErr, GetNewMBar);
  5144.     
  5145.     // install menus
  5146.     SetMenuBar(menuBar);    
  5147.     DisposeHandle(menuBar);
  5148.  
  5149.     // Build the font menu
  5150.     anErr = BuildFontMenu(GetMenuHandle(mFont));
  5151.     nrequire(anErr, BuildFontMenu);
  5152.     
  5153.     // insert our heirarchical menus
  5154.     {
  5155.     MenuHandle     menu = MacGetMenu( mVoices );
  5156.     short        menuID, itemID;
  5157.     
  5158.     InsertMenu( menu, hierMenu );
  5159.     
  5160.     CommandToIDs(cSelectVoice, &menuID, &itemID);
  5161.     menu = GetMenuHandle(menuID);
  5162.  
  5163.     SetItemCmd( menu, itemID, hMenuCmd );
  5164.     SetItemMark( menu, itemID, mVoices );
  5165.     }
  5166.  
  5167.     if (!AdjustMenus(nil, true, false))
  5168.         DrawMenuBar();
  5169.     
  5170.     // start up QuickTime, but problems result in us pretending not to have it
  5171. #if ALLOW_QUICKTIME
  5172.     if (gMachineInfo.haveQuickTime)
  5173.         if (EnterMovies() != noErr)
  5174.             gMachineInfo.haveQuickTime = false;
  5175. #endif
  5176.         
  5177.     // Install AppleEvent handlers for the base classes
  5178.  
  5179.     #define INSTALL(event, handler) \
  5180.             AEInstallEventHandler(kCoreEventClass, event, handler, 0, false)
  5181.     // AEC, changed to use the correct handler procs
  5182.     INSTALL (kAEOpenApplication, NewAEEventHandlerProc(DoOpenApp));
  5183.     INSTALL ('rapp', NewAEEventHandlerProc(DoReopenApp));
  5184.     INSTALL (kAEQuitApplication, NewAEEventHandlerProc(DoQuitApp));
  5185.     INSTALL (kAEOpenDocuments,   NewAEEventHandlerProc(DoOpenDocument));
  5186.     INSTALL (kAEPrintDocuments,  NewAEEventHandlerProc(DoPrintDocument));
  5187.  
  5188.     #undef INSTALL
  5189.     
  5190.     // AEC, added control procs
  5191.     gVActionProc = NewControlActionProc(VActionProc);
  5192.     gHActionProc = NewControlActionProc(HActionProc);
  5193.  
  5194.  
  5195.     // Install our global dragging procs, but only if we have Drag and Drop. An error results
  5196.     // in us pretending that we don't have drag support. Notice that in the test above, we also
  5197.     // require TextEdit to have TEGetHiliteRgn avalilable, which is always the case with the
  5198.     // present Drag Manager.
  5199.  
  5200.     if (gMachineInfo.haveDragMgr)
  5201.         {
  5202.         gGlobalTrackingHandler = NewDragTrackingHandlerProc(GlobalTrackingHandler);
  5203.         gGlobalReceiveHandler = NewDragReceiveHandlerProc(GlobalReceiveHandler);
  5204.         
  5205.         anErr = InstallTrackingHandler(gGlobalTrackingHandler, nil, nil);
  5206.  
  5207.         if (anErr == noErr)
  5208.             {
  5209.             anErr = InstallReceiveHandler(gGlobalReceiveHandler, nil, nil);
  5210.  
  5211.             if (anErr != noErr)
  5212.                 {
  5213.                 RemoveTrackingHandler(gGlobalTrackingHandler, nil);
  5214.                 gMachineInfo.haveDragMgr = false;
  5215.                 }
  5216.             }
  5217.         else
  5218.             gMachineInfo.haveDragMgr = false;
  5219.         }
  5220.  
  5221.     // for AppleScript
  5222.     anErr = OpenADefaultComponent(kOSAComponentType, kOSAGenericScriptingComponentSubtype, &gOSAComponent);
  5223.  
  5224.     return noErr;
  5225.     
  5226.     
  5227. // EXCEPTION HANDLING
  5228. BuildFontMenu:
  5229. GetNewMBar:
  5230. // SysEnvirons:
  5231.     ConductErrorDialog(anErr, cNull, cancel);
  5232.     
  5233.     return anErr;
  5234.  
  5235. } // DoInitialize
  5236.  
  5237. // --------------------------------------------------------------------------------------------------------------
  5238. #pragma segment Terminate
  5239.  
  5240. static OSErr    DoTerminate(void)
  5241. {
  5242.     OSErr    anErr = noErr;
  5243.     
  5244.     if (gFontThread != kNoThreadID)
  5245.         DisposeThread(gFontThread, &gThreadResults, false);
  5246.     if (gStarterThread != kNoThreadID)
  5247.         DisposeThread(gStarterThread, &gThreadResults, false);
  5248.  
  5249. #if ALLOW_QUICKTIME
  5250.     if (gMachineInfo.haveQuickTime)
  5251.         ExitMovies();
  5252. #endif
  5253.         
  5254.     if (gMachineInfo.haveTSMTE)
  5255.         CloseTSMAwareApplication();
  5256.  
  5257.     if (gMachineInfo.haveDragMgr)
  5258.         {
  5259.         RemoveReceiveHandler(gGlobalReceiveHandler, nil);
  5260.         RemoveTrackingHandler(gGlobalTrackingHandler, nil);
  5261.         }
  5262.  
  5263.     if (gMachineInfo.haveAppearanceMgr)
  5264.         UnregisterAppearanceClient();
  5265.         
  5266.     // for AppleScript
  5267.     if (gOSAComponent)
  5268.         CloseComponent(gOSAComponent);
  5269.  
  5270.     return anErr;
  5271.     
  5272. } // DoTerminate
  5273.  
  5274. // --------------------------------------------------------------------------------------------------------------
  5275. #pragma segment Main
  5276.  
  5277. int main(int argc, char *argv[])
  5278. {
  5279. #pragma unused (argc, argv)
  5280.  
  5281.     OSErr    anErr;
  5282.     
  5283. #ifndef __MWERKS__
  5284.     UnloadSeg((Ptr) _DataInit);                        /* note that _DataInit must not be in Main! */
  5285. #endif
  5286. //Not for Carbon anymore!
  5287. //    MaxApplZone();                                    /* expand the heap so code segments load at the top */
  5288. //    MoreMasters(); MoreMasters(); MoreMasters();     /* we love handles */
  5289. #ifdef __MWERKS__
  5290. #if __option(profile)
  5291.     ProfilerInit(collectSummary, bestTimeBase, 500, 10);
  5292. #endif
  5293. #endif
  5294.     anErr = DoInitialize();
  5295. #ifdef __MWERKS__
  5296. #if __option(profile)
  5297.     ProfilerDump("\pboot.prof");
  5298.     ProfilerSetStatus(false);
  5299.     ProfilerClear();
  5300. #endif
  5301. #endif
  5302.     UnloadSeg((Ptr) DoInitialize);                    
  5303.     if (anErr == noErr)
  5304.         {
  5305.         DoEventLoop();
  5306.  
  5307. #ifdef __MWERKS__
  5308. #if __option(profile)
  5309.         ProfilerTerm();
  5310. #endif
  5311. #endif
  5312.  
  5313. // REVIEW: don't want to unload the segment we're in!!
  5314. //        UnloadSeg((Ptr) DoEventLoop);
  5315.         DoTerminate();                    
  5316.         }
  5317.     return 0;
  5318. } // main
  5319.